
/*
 *  
 *
 *  Copyright (C) Microsoft Corporation.  All rights reserved
 *
 *  CrmConnector.cs - All the crm calls are made in this file.
 *  
 */

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;
using System.IO;
using System.Collections.Specialized;
using System.Reflection;
using System.Xml;
using System.Windows.Forms;
using System.Collections;
using System.Diagnostics;
using System.Threading;
using Microsoft.Crm.DataBindining;



namespace CRMScenarios
{
    /// <summary>
    /// This class handles all the calls going to CRM server.
    /// </summary>
    public static class CrmConnector
    {
        /* 
         * All the CrmServer related variables and the local cache.
         * 
         * List of permitted activities and child entities
         */ 
        
        private static string _CrmServer = null;
        private static CrmService _CrmService = null;
        private static MetadataService _MetadataService = null;
        private static WhoAmIResponse User = null;
        private static Dictionary<string, EntityMetadata> NameToEntityMetaDataMapping = null;
        private static Dictionary<string, string[][]> parsedFromXmlBase = null;
        private static Dictionary<string, string[]> NameDisplayPluralMapping = null;
        private static DateTime MetaDataInitTime;
        private static Dictionary<string, EntityMetadata> ActivityMetaData = null;
        private static Dictionary<string, EntityMetadata> RestOfEntities = null;
        private static StringCollection ActivitiesCollection = null;
        private static RolePrivilege[] Privileges = null;
        private static Dictionary<string, bool> PrivilegeCache = null;
        private static string[] activites = new string[] { 
                                                    "task", 
                                                    "fax", 
                                                    "phonecall", 
                                                    "email", 
                                                    "letter", 
                                                    "appointment",  
                                                    "serviceappointment", 
                                                    "campaignresponse"  
                                                    };
        private static StringCollection ChildEntitiesCollection = null;
        private static string[] ChildEntities = new string[] {  
                                                    "discount", 
                                                    "bulkoperationlog", 
                                                    "activitymimeattachment", 
                                                    "salesorderdetail", 
                                                    "kbarticlecomment", 
                                                    "quotedetail", 
                                                    "productpricelevel", 
                                                    "calendarrule", 
                                                    "userfiscalcalendar", 
                                                    "activityparty", 
                                                    "uom", 
                                                    "fixedmonthlyfiscalcalendar", 
                                                    "quarterlyfiscalcalendar", 
                                                    "annualfiscalcalendar", 
                                                    "invoicedetail", 
                                                    "contractdetail", 
                                                    "relationshiprolemap", 
                                                    "opportunityproduct", 
                                                    "semiannualfiscalcalendar", 
                                                    "salesliteratureitem", 
                                                    "monthlyfiscalcalendar"
                                                    };

        /// <summary>
        /// Read in the lists to an easily readable structure.
        /// </summary>
        static CrmConnector()
        {
            ActivitiesCollection = ArrayToCollection(activites);
            ChildEntitiesCollection = ArrayToCollection(ChildEntities);
            MetaDataInitTime = System.DateTime.Now;
        }


        /// <summary>
        /// Try to login to the CRM server. 
        /// Also try for metadata services.
        /// </summary>
        /// <param name="targetServerURL"></param>
        /// <returns></returns>
        public static bool Login(string targetServerURL)
        {
            if (User != null)
            {
                return true;
            }
            bool retValue = false;
            _CrmServer = targetServerURL;
            _CrmService = new CrmService();
            _MetadataService = new MetadataService();
            _CrmService.Url = _CrmServer + "/mscrmservices/2006/crmservice.asmx";
            _MetadataService.Url = _CrmServer + "/mscrmservices/2006/metadataservice.asmx";
            _CrmService.UnsafeAuthenticatedConnectionSharing = true;
            _MetadataService.UnsafeAuthenticatedConnectionSharing = true;
            _CrmService.Credentials = CredentialCache.DefaultCredentials;
            _MetadataService.Credentials = CredentialCache.DefaultCredentials;


            WhoAmIRequest wr = new WhoAmIRequest();

            try
            {
                User = (WhoAmIResponse)_CrmService.Execute(wr);

                if (User != null)
                {
                    retValue = true;
                }
            }
            // USE CRMEXCEPTION WITH DEFINED MESSAGE STRING
            catch (Exception)
            {
                // TODO - catch proper exp.
            }

            return retValue;
        }

        /// <summary>
        /// Check for the age of metadata. 
        /// </summary>
        /// <returns></returns>
        private static bool IsMetaDataOld()
        {
            System.TimeSpan duration = DateTime.Now.Subtract(MetaDataInitTime);
            if (duration.Minutes > ConfigFileManager.GetMetaDataTimeOut(120))
            {
                CacheManager.SetRefreshMDCacheBit(true);
                return true;
            }

            return false;
        }

        /// <summary>
        /// Read in the metadata from the server by making the call,
        /// Read in the Privilege set.
        /// Parse the data and put in the local cache,
        /// </summary>
        private static void initializeMetaData()
        {
            Metadata metadata = null;
            try
            {
                metadata = _MetadataService.RetrieveMetadata(MetadataFlags.All);
            }
            catch (Exception)
            {
                Util.ShowError(global::CRMScenarios.Resources.MetaDataInitFailureMessage);
                return;
            }

            RetrieveUserPrivilegesRequest retrievePrReq = new RetrieveUserPrivilegesRequest();
            retrievePrReq.UserId = User.UserId;
            RetrieveUserPrivilegesResponse retrievePrRes = null;
            try
            {
                 retrievePrRes = (RetrieveUserPrivilegesResponse)_CrmService.Execute(retrievePrReq);
            }
            catch
            {
                Util.ShowError(global::CRMScenarios.Resources.MetaDataInitFailureMessage);
                return;
            }

            if ((retrievePrRes.RolePrivileges == null) || (metadata == null))
            {
                Util.ShowError(global::CRMScenarios.Resources.MetaDataInitFailureMessage);
                return;
            }

            Privileges = retrievePrRes.RolePrivileges;

            //here we have got the metadata..
            //lets set the time.
            MetaDataInitTime = System.DateTime.Now;
            CacheManager.SetRefreshMDCacheBit(false);
            NameToEntityMetaDataMapping = new Dictionary<string, EntityMetadata>();
            parsedFromXmlBase = new Dictionary<string, string[][]>();
            ActivityMetaData = new Dictionary<string, EntityMetadata>();
            RestOfEntities = new Dictionary<string, EntityMetadata>();
            NameDisplayPluralMapping = new Dictionary<string, string[]>();
            PrivilegeCache = new Dictionary<string, bool>(Privileges.Length * 3);

            StringCollection ExcludedEntities = ConfigFileManager.GetEntityExclusionList2();

            for (int i = 0; i < metadata.Entities.Length; i ++)
            {
                EntityMetadata entityMeta = metadata.Entities[i];
                // dont use the other signature. 
                if (hasPrivilege(ref entityMeta, PrivilegeType.Read) == false) 
                {
                    continue;
                }

                string name = entityMeta.Name;

                if ((ExcludedEntities != null) &&
                    ((ExcludedEntities.Contains(name)) /*||(ExcludedEntities.Contains(entityMeta.DisplayName))*/))
                {
                    continue;
                }

                NameDisplayPluralMapping.Add(name, new string[] { entityMeta.DisplayName, entityMeta.DisplayCollectionName });

                if ((entityMeta.IsCustomizable == true) && (ChildEntitiesCollection.Contains(name) != true))
                {
                    NameToEntityMetaDataMapping.Add(name, entityMeta);
                    continue;
                }

                if (ActivitiesCollection.Contains(name) == true)
                {
                    ActivityMetaData.Add(name, entityMeta);
                    continue;
                }
                //if (entityMeta.IsCustomizable == true)
                //if(ChildEntitiesCollection.Contains(name))
                //{
                RestOfEntities.Add(name, entityMeta);
                //}
            }

            // WE DONT NEED ACTIVITY POINTER and the others. 
            // LETS REMOVE IT.

            RestOfEntities.Remove("activitypointer");
            RestOfEntities.Remove("campaignitem");
            RestOfEntities.Remove("listmember");
            RestOfEntities.Remove("campaignactivityitem");
            RestOfEntities.Remove("activityparty"); // NOT NEEDED.
        }

        /// <summary>
        /// From the mapping, change the real name to plural name.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static string NameToPlural(string name)
        {
            try
            {
                return NameDisplayPluralMapping[name][1];
            }
            catch { }
            return null;
        }

        /// <summary>
        /// From the mapping, change the real name to display name.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static string NameToDisplay(string name)
        {
            try
            {
                return NameDisplayPluralMapping[name][0];
            }
            catch { }
            return null;
        }

        /// <summary>
        /// Loop throuhg the enitiee, check for the privilege, 
        /// add them to the return list 
        /// return list is of [diplay name][real name]
        /// first array ddisplay name. second - real name.
        /// </summary>
        /// <param name="privilegeNeeded"></param>
        /// <returns></returns>
        public static string[][] getEntityListFromCRM(PrivilegeType privilegeNeeded)
        {
            string[][] retArray = new string[2][];
            if (IsMetaDataOld() || (NameToEntityMetaDataMapping == null) || (ActivityMetaData == null))
            {
                initializeMetaData();
            }

            retArray[0] = new string[NameToEntityMetaDataMapping.Count];
            retArray[1] = new string[NameToEntityMetaDataMapping.Count];
            NameToEntityMetaDataMapping.Keys.CopyTo(retArray[1], 0); // first array - display name - so to second array
            for (int i = 0; i < retArray[1].Length; i++)
            {
                // seond array - real name. gives the Disp+Plur from NameDisplayPluralMapping where 0'th is display name.
                retArray[0][i] = NameDisplayPluralMapping[retArray[1][i]][0];
            }

            if (privilegeNeeded == PrivilegeType.Read)
            {
                return retArray;
            }

            StringCollection retList = new StringCollection();

            foreach (string s in retArray[1])
            {
                // CHECK THE NECESSARY PRIVILEGES FOR THIS OPERATION
                if (hasPrivilege(s, privilegeNeeded) == true)
                {
                    retList.Add(s);
                }
            }

            string[][] retArrayWithWrite = new string[2][];
            retArrayWithWrite[1] = new string[retList.Count];
            retList.CopyTo(retArrayWithWrite[1], 0); // first array - display name - so to second array
            for (int i = 0; i < retArrayWithWrite[1].Length; i++)
            {
                // seond array - real name. gives the Disp+Plur from NameDisplayPluralMapping where 0'th is display name.
                retArrayWithWrite[0][i] = NameDisplayPluralMapping[retArrayWithWrite[1][i]][0];
            }
            return retArrayWithWrite;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entityName"></param>
        /// <returns></returns>
        public static bool IsNonMainEntity(string entityName)
        {
            return ( ChildEntitiesCollection.Contains(entityName) || RestOfEntities.ContainsKey(entityName) );
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entityName"></param>
        /// <returns></returns>
        public static bool IsChildEntity(string entityName)
        {
            return ChildEntitiesCollection.Contains(entityName);
        }

        /// <summary>
        /// Retrieve the metadata from the dictionary/local cache.
        /// </summary>
        /// <param name="entityName"></param>
        /// <returns></returns>
        public static EntityMetadata GetEntityMetaData(string entityName)
        {
            if (entityName == null)
            {
                return null;
            }

            if (IsMetaDataOld() || (NameToEntityMetaDataMapping == null) || (ActivityMetaData == null))
            {
                initializeMetaData();
            }

            EntityMetadata retMetaData = null;
            if (NameToEntityMetaDataMapping.ContainsKey(entityName))
            {
                retMetaData = NameToEntityMetaDataMapping[entityName]; // name must be logical name.
            }
            else if (ActivityMetaData.ContainsKey(entityName))
            {
                retMetaData = ActivityMetaData[entityName];
            }
            else if (RestOfEntities.ContainsKey(entityName))
            {
                retMetaData = RestOfEntities[entityName];
            }

            return retMetaData;
        }

        /// <summary>
        /// Get the type of given attribute for the given entity
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="attibuteName"></param>
        /// <returns></returns>
        public static AttributeType GetAttributeType(string entityType, string attibuteName)
        {
            EntityMetadata eMeta = GetEntityMetaData(entityType);
            if (eMeta == null)
            {
                return AttributeType.Virtual;
            }

            foreach (AttributeMetadata attr in eMeta.Attributes)
            {
                if (attr.Name == attibuteName)
                {
                    return attr.Type;
                }
            }

            return AttributeType.Virtual;                // supposed to be unKnown.
        }

        /// <summary>
        /// Get the related entity list. 
        /// A tricky one
        /// 
        /// 2 types of relation ships
        ///     - From 
        ///     - To
        /// 
        /// Get the list of all the "TO" relationships, check for privilege, add to the list.
        /// 
        /// then 
        /// Get the list of all the "FROM" relationships, check for privilege, add to the list.
        /// </summary>
        /// <param name="entityName"></param>
        /// <param name="privilegeNeeded"></param>
        /// <returns></returns>
        public static string[][] GetRelatedEntityList(string entityName, PrivilegeType privilegeNeeded)
        {
            if (entityName == null)
            {
                return null;
            }

            StringCollection relatedList = new StringCollection();
            EntityMetadata entityMeta = GetEntityMetaData(entityName);

            // CHECK FOR REFERENCES_from AS WELL
            RelationshipMetadata[] relMetaTo = entityMeta.ReferencesTo;
            RelationshipMetadata[] relMetaFrom = entityMeta.ReferencesFrom;

            // This is the check for relatedTO
            foreach (RelationshipMetadata relative in relMetaTo)
            {
                if ((relative.ReferencedEntity == relative.ReferencingEntity) &&
                    (relative.ReferencedAttribute == relative.ReferencingAttribute))
                {
                    continue;
                }
                if (hasPrivilege(relative.ReferencingEntity, privilegeNeeded) &&
                    ((relatedList.IndexOf(relative.ReferencingEntity)) < 0))
                {
                    relatedList.Add(relative.ReferencingEntity);
                }
            }

            // This is the check for relatedFrom
            foreach (RelationshipMetadata relative in relMetaFrom)
            {
                if ((relative.ReferencedEntity == relative.ReferencingEntity) &&
                    (relative.ReferencedAttribute == relative.ReferencingAttribute))
                {
                    continue;
                }
                if (hasPrivilege(relative.ReferencedEntity, privilegeNeeded) &&
                    ((relatedList.IndexOf(relative.ReferencedEntity)) < 0))
                {
                    relatedList.Add(relative.ReferencedEntity);
                }
            }

            relatedList = ArrayToCollection(ExcludeFirstFromSecond2(CollectionToArray(ConfigFileManager.GetExclusionList2(entityName, "related")), CollectionToArray(relatedList)));

            string[][] returnArray = new string[2][];
            returnArray[0] = new string[relatedList.Count];
            returnArray[1] = new string[relatedList.Count];
            relatedList.CopyTo(returnArray[1], 0); // second array holds the real name.
            for (int i = 0; i < returnArray[1].Length; i++)
            {
                returnArray[0][i] = NameDisplayPluralMapping[returnArray[1][i]][1]; // Plural name is at position 2.
                if (returnArray[0][i] == null)
                {
                    returnArray[0][i] = NameDisplayPluralMapping[returnArray[1][i]][0];
                }
                if (returnArray[0][i] == null)
                {
                    returnArray[0][i] = returnArray[1][i];
                }
            }

            return returnArray;
        }

        /// <summary>
        /// Check for the given guid in the collection. Guid corresponds to a privilege.
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        private static bool IsThisPrivilegeAvailable(string guid)
        {
            foreach(RolePrivilege rolePrv in Privileges)
            {
                if (rolePrv.PrivilegeId.ToString().Equals(guid))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Check for the privilege which is asked for.
        /// </summary>
        /// <param name="entityName"></param>
        /// <param name="privilegeNeeded"></param>
        /// <returns></returns>
        public static bool hasPrivilege(string entityName, PrivilegeType privilegeNeeded)
        {
            if (!NameToEntityMetaDataMapping.ContainsKey(entityName) && !RestOfEntities.ContainsKey(entityName))
            {
                return false;
            }

            if (IsChildEntity(entityName) && (privilegeNeeded == PrivilegeType.Read))
            {
                // TODO - dont give privilege just like that.. u have to check for the parent.
                return true;
            }

            if (NameToEntityMetaDataMapping.ContainsKey(entityName))
            {
                EntityMetadata eMeta = NameToEntityMetaDataMapping[entityName];
                return hasPrivilege(ref eMeta, privilegeNeeded);
            }
            if (RestOfEntities.ContainsKey(entityName))
            {
                EntityMetadata eMeta = RestOfEntities[entityName];
                return hasPrivilege(ref eMeta, privilegeNeeded);
            }
            return false;
        }

        /// <summary>
        /// The same stuff in the other hasPrivilege call, but this has made use of the cache. 
        /// So that function calls this indirectly.
        /// 
        /// If not found in cache, uses a brute force method to find out the privilege, (loop)
        /// then puts in cache for future purposes.
        /// </summary>
        /// <param name="entityMeta"></param>
        /// <param name="privilegeNeeded"></param>
        /// <returns></returns>
        public static bool hasPrivilege(ref EntityMetadata entityMeta, PrivilegeType privilegeNeeded)
        {
            if (IsChildEntity(entityMeta.Name) && (privilegeNeeded == PrivilegeType.Read))
            {
                // TODO - dont give privilege just like that.. u have to check for the parent.
                return true;
            }
            bool retVal = false;
            foreach (SecurityPrivilege privilege in entityMeta.Privileges)
            {
                if (privilege.PrivilegeType == privilegeNeeded)
                {
                    string prvId = privilege.PrivilegeId.ToString();
                    if (PrivilegeCache.ContainsKey(prvId))
                    {
                        return PrivilegeCache[prvId];
                    }
                    retVal = IsThisPrivilegeAvailable(prvId);
                    PrivilegeCache.Add(prvId, retVal);
                    break;
                }
            }
            return retVal;
        }


        /// <summary>
        /// Given a collection, convert it to an array.
        /// </summary>
        /// <param name="collection"></param>
        /// <returns></returns>
        public static string[] CollectionToArray(StringCollection collection)
        {
            string[] array = null;
            if (collection == null)
            {
                return array;
            }
            array = new string[collection.Count];
            collection.CopyTo(array, 0);
            return array;
        }

        /// <summary>
        /// Given an array convert it to a collection.
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public static StringCollection ArrayToCollection(string[] array)
        {
            StringCollection collection = null;
            if (array == null)
            {
                return collection;
            }
            collection = new StringCollection();
            foreach (string s in array)
            {
                collection.Add(s);
            }
            return collection;
        }

        /// <summary>
        /// May be a bit confusing. 
        /// 
        /// first is a set of strings, and same with second. 
        /// 
        /// this function returns a new set first - second. 
        /// (is set theory operation "-")
        /// </summary>
        /// <param name="first"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        private static string[] ExcludeFirstFromSecond2(string[] first, string[] second)
        {
            if ((first == null) || (second == null))
            {
                return second;
            }
            List<string> firstList = new List<string>(first);
            List<string> secondList = new List<string>(second);
            List<string> tmpList = new List<string>(second);

            // EXPLORE THE OTHER SORT OVERLOADS AND LOOK FOR CultureInfo STUFF
            // made a search and cudnt find any culture invariant. anyway some comparator things are there.
            // didnt make use of that as of now.

            firstList.Sort();
            secondList.Sort();
            int length = secondList.Count;

            for (int i = 0; i < length; i++)
            {
                tmpList[i] = secondList[i];
            }

            foreach (string s in firstList)
            {
                int index = tmpList.BinarySearch(s);
                if (index >= 0)
                {
                    secondList.RemoveAt(index);
                    length--;
                }
            }

            string[] ret = new string[length];
            secondList.CopyTo(ret, 0);
            return ret;
        }

        /// <summary>
        /// May be a bit confusing. 
        /// 
        /// first is a set of strings, and same with second. 
        /// 
        /// this function returns a new set first - second. 
        /// (is set theory operation "-")
        /// </summary>
        /// <param name="first"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        private static string[] ExcludeFirstFromSecond(string[] first, string[] second)
        {
            if ((first == null) || (second == null))
            {
                return second;
            }
            List<string> firstList = new List<string>(first);
            List<string> secondList = new List<string>(second);

            // EXPLORE THE OTHER SORT OVERLOADS AND LOOK FOR CultureInfo STUFF
            // made a search and cudnt find any culture invariant. anyway some comparator things are there.
            // didnt make use of that as of now.

            firstList.Sort();
            secondList.Sort();
            int length = secondList.Count;

            foreach (string s in firstList)
            {
                int index = secondList.BinarySearch(s);
                if (index >= 0)
                {
                    secondList.RemoveAt(index);
                    length--;
                }
            }

            string[] ret = new string[length];
            secondList.CopyTo(ret, 0);
            return ret;
        }

        /// <summary>
        /// Do deal with the regular expresions used.
        /// </summary>
        /// <param name="searchValue"></param>
        /// <returns></returns>
        public static string ConvertUserFindToLike(string searchValue)
        {
            StringBuilder result = new StringBuilder(searchValue.Length * 2);

            char[] tmp = searchValue.ToCharArray();

            for (int i = 0; i < searchValue.Length; i++)
            {
                switch (tmp[i])
                {
                    case '%': result.Append("[%]"); break;
                    case '_': result.Append("[_]"); break;
                    case '[': result.Append("[[]"); break;
                    case '*': result.Append('%'); break;
                    default: result.Append(tmp[i]); break;
                }
            }

            // If there is not wild card at the end of this string, add one
            if (searchValue.Length == 0 || tmp[tmp.Length - 1] != '*')
            {
                result.Append('%');
            }

            return result.ToString();
        }

        /// <summary>
        /// Do the XmlEncoding. Straight forward code.
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        private static string XmlEncode(string xml)
        {
            //LATER: (TobinZ, 2005-06-15) - Remove this function and convert all users to XmlTextWriter.
            if (xml != null && xml.Length > 0)
            {
                StringBuilder encodedXml = new StringBuilder(xml);
                encodedXml.Replace("&", "&amp;");
                encodedXml.Replace("<", "&lt;");
                encodedXml.Replace(">", "&gt;");
                encodedXml.Replace("\"", "&quot;");
                encodedXml.Replace("'", "&apos;");
                return encodedXml.ToString();
            }
            else
            {
                return String.Empty;
            }
        }


        /// <summary>
        /// Tricky!! 
        /// If you are looking for particular types (Example - lookup)
        /// You would have been forced to write something whicch is not what you 
        /// really meant. 
        /// 
        /// Replacing a "id" at the end by a "name" would make you have what you want.
        /// </summary>
        /// <param name="EntityType"></param>
        /// <param name="FetchXML"></param>
        /// <returns></returns>
        private static string FixQuickFindFilter(string EntityType, string FetchXML)
        {
            // Load the FetchXML into a DOM
            XmlDocument fetchXMLDOC = Util.CreateXmlDocument(FetchXML);

            // Get the filter node that has the quick find fields
            XmlNodeList quickFindFields = fetchXMLDOC.SelectNodes("/fetch/entity//filter[@isquickfindfields=1]/condition");
            //Debug.AssertEx(quickFindFields != null, "There are no Quick Find Fields configured in the Quick Find View of this Entity.");
            //Debug.AssertEx(quickFindFields.Count != 0, "Quick Find View of this Entity contains a Quick Find Filter but no Fields within it.");

            EntityMetadata entityMetadata = GetEntityMetaData(EntityType);
            AttributeMetadata attrMetadata = null;
            string attrName;
            foreach (XmlNode quickFindCondition in quickFindFields)
            {
                attrName = quickFindCondition.Attributes["attribute"].Value;

                foreach (AttributeMetadata aMeta in entityMetadata.Attributes)
                {
                    if (aMeta.Name == attrName)
                    {
                        attrMetadata = aMeta;
                    }
                }

                if (attrMetadata == null)
                {
                    continue;
                }


                switch (attrMetadata.Type.ToString().ToLower(System.Globalization.CultureInfo.InvariantCulture))
                {
                    //we have to replace the attribute with the named column for these types
                    case "lookup":
                    case "customer":
                    case "owner":
                    case "picklist":
                    case "bit":
                    case "state":
                    case "status":

                        string searchAttr = quickFindCondition.Attributes["attribute"].Value;
                        if ((searchAttr.Length > 0) &&
                            (searchAttr.ToLower(CultureInfo.InvariantCulture).LastIndexOf("id", System.StringComparison.InvariantCulture) == searchAttr.Length - 2))
                        {
                            quickFindCondition.Attributes["attribute"].Value = searchAttr + "name";
                        }
                        break;
                }
            }
            return fetchXMLDOC.OuterXml;
        }

        /// <summary>
        /// Process the quickfindxml according to the searchcriteria. 
        /// Depending on whether it is "number", "money", "date", or something else.
        /// </summary>
        /// <param name="SearchCriteria"></param>
        /// <param name="quickFindXml"></param>
        /// <param name="entityType"></param>
        /// <returns></returns>
        private static string ProcessQuickFindSearchCriteria(string SearchCriteria, string quickFindXml, string entityType)
        {
            if ((SearchCriteria == null) || (quickFindXml == null) || (entityType == null))
            {
                return null;
            }

            quickFindXml = FixQuickFindFilter(entityType, quickFindXml);

            //Debug.Assert(SearchCriteria != null && SearchCriteria.Length != 0, "Quick find search string cannot be null or empty");

            // If the search criteria is a * then return back all records
            // for this we have to delete the quickfind filter node from the QueryXml

            // Load the QuickFind filter into a DOM
            XmlDocument queryXmlDOM = Util.CreateXmlDocument(quickFindXml);
            XmlNode searchFields = queryXmlDOM.SelectSingleNode("fetch/entity/filter[@isquickfindfields=1]");

            if (searchFields == null)
            {
                // Check for nested filters
                searchFields = queryXmlDOM.SelectSingleNode("fetch/entity/filter/filter[@isquickfindfields=1]");
            }

            // Hardcoded Fetch for lookups where QuickFindFields is not defined
            if (searchFields == null)
            {
                //string objectName = Util.GetObjName(returnedTypeCode);
                string primaryFieldName = GetEntityMetaData(entityType).PrimaryField;
                StringBuilder newFetch = new StringBuilder();

                newFetch.Append("<fetch version=\"1.0\" output-format=\"xml-platform\" mapping=\"logical\" page=\"1\" count=\"50\">");
                newFetch.Append("<entity name=\"");
                newFetch.Append(entityType);
                newFetch.Append("\">");
                newFetch.Append("<attribute name=\"" + primaryFieldName + "\"/>");
                newFetch.Append("<filter type=\"or\" isquickfindfields=\"1\">");
                newFetch.Append("<condition attribute=\"");
                newFetch.Append(primaryFieldName);
                newFetch.Append("\"");
                newFetch.Append(" operator=\"like\" value=\"{0}\" />");
                newFetch.Append("</filter>");
                newFetch.Append("</entity>");
                newFetch.Append("</fetch>");

                queryXmlDOM = Util.CreateXmlDocument(newFetch.ToString());
                searchFields = queryXmlDOM.SelectSingleNode("fetch/entity/filter");
            }

            if (SearchCriteria == "*")
            {
                // create regexp object for digits, i.e. {0..9} and do ismatch
                Regex digitExp = new Regex(@"{\d}");
                foreach (XmlNode conditionNode in searchFields.SelectNodes("condition"))
                {
                    if (digitExp.IsMatch(conditionNode.Attributes["value"].Value))
                    {
                        conditionNode.ParentNode.RemoveChild(conditionNode);
                    }
                }

                // If searchFields has no more children, remove it, prevents empty filters
                if (searchFields.ChildNodes.Count == 0)
                {
                    searchFields.ParentNode.RemoveChild(searchFields);
                }

                return queryXmlDOM.OuterXml;
            }

            // Save the user entered search string, we will use it for figuring out datatype of the search string
            string OriginalSearchString = SearchCriteria;
            // Strip out the begining and ending * in the saved original string
            bool StartsWithAsterix = (SearchCriteria.IndexOf('*') == 0);
            bool EndsWithAsterix = (SearchCriteria.Length > 0 && SearchCriteria.LastIndexOf('*') == SearchCriteria.Length - 1);
            if (StartsWithAsterix && EndsWithAsterix)
            {
                OriginalSearchString = SearchCriteria.Substring(1, SearchCriteria.Length - 2);
            }
            else if (StartsWithAsterix)
            {
                OriginalSearchString = SearchCriteria.Substring(1, SearchCriteria.Length - 1);
            }
            else if (EndsWithAsterix)
            {
                OriginalSearchString = SearchCriteria.Substring(0, SearchCriteria.Length - 1);
            }

            // fix the input filter
            // ConvertUserFindToLike doesn't fix up non-XML friendly characters.
            SearchCriteria = XmlEncode(ConvertUserFindToLike(SearchCriteria));

            // We need the organization settings for parsing dates and numbers
            //OrganizationSettings orgSettings = OrganizationCache.RetrieveOrganization(UserCache.GetCurrentUser()).Settings;


            // We need a culture info that will be based on the organization settings
            CultureInfo ci = CultureInfo.InvariantCulture; // orgSettings.OrgCultureInfo;

            // Now Figure out the datatype of the user entered SearchCriteria

            // Try to parse as a decimal and integer
            string SearchCriteriaAsDecimal = String.Empty;
            string SearchCriteriaAsInteger = String.Empty;
            //Is search string a float
            bool SearchCriteriaIsFloat = false;
            bool SearchCriteriaIsInteger = false;
            //Is search string a currency
            bool SearchCriteriaIsCurrency = false;
            try
            {
                Decimal num = Decimal.Parse(OriginalSearchString, NumberStyles.Currency, ci.NumberFormat);
                SearchCriteriaAsInteger = SearchCriteriaAsDecimal = num.ToString(System.Globalization.CultureInfo.InvariantCulture);
                SearchCriteriaIsCurrency = SearchCriteriaIsInteger = SearchCriteriaIsFloat = true;

                // Now we check to see if this decimal should be treated as an Integer, Float, Currency
                // We have to treat the entered string as an integer if
                // 1. It has no currency symbol in it
                // 2. Has no decimal separator in it
                // Float if
                // 1. It has no currency symbol in it
                // Currency
                // Any valid number with or without currency symbol.
                // Currency is a superset of Float, Interger, Currency

                // check if there is a currency symbol
                ////////////////if (OriginalSearchString.IndexOf(orgSettings.CurrencySymbol) != -1)
                ////////////////{
                ////////////////    //if there is a currency symbol we dont treat this search string as a float or a integer
                ////////////////    //we will use the SearchCriteriaAsDecimal for the currency field so dont clear that out
                ////////////////    SearchCriteriaIsFloat = false;
                ////////////////    SearchCriteriaIsInteger = false;
                ////////////////    SearchCriteriaAsInteger = String.Empty;

                ////////////////}
                // check if there is a decimal seperator in the search string
                // the SearchCriteriaIsInteger is to optimize runtime so that we dont execute unecessary code
                if (SearchCriteriaIsInteger &&
                    OriginalSearchString.IndexOf(ci.NumberFormat.NumberDecimalSeparator, System.StringComparison.InvariantCulture) != -1)
                {
                    //if so then we dont treat this as a integer
                    SearchCriteriaIsInteger = false;
                    SearchCriteriaAsInteger = String.Empty;
                }

            }
            catch (FormatException)
            {
                // Do Nothing, thrown by Decimal.Parse
            }
            catch (OverflowException)
            {
                // Do Nothing, thrown by Decimal.Parse
            }

            // Try to parse as a date
            string SearchCriteriaAsDate = String.Empty;
            bool SearchCriteriaIsDate = false;
            // Only try parsing if the search is not already determined to be a number
            // no need to check for Integer, Float because Integer, Float is a subset case of currency
            if (!SearchCriteriaIsCurrency)
            {
                try
                {
                    DateTime dt = DateTime.Parse(OriginalSearchString, ci.DateTimeFormat);
                    SearchCriteriaAsDate = dt.ToString("s", ci.DateTimeFormat);
                    SearchCriteriaIsDate = true;
                }
                catch (FormatException)
                {
                    // Do nothing exception thrown by DateTime.Parse
                }
                catch (ArgumentOutOfRangeException)
                {
                    //For cases when the year may be out of range
                    //DateTime.Parse tries to parse 01 23456 as a date and throws an OutofRangeException because
                    //23456 is not within 1-9999 i.e. year
                }
                catch (IndexOutOfRangeException)
                {
                    //The strings -99t to 99t cause DateTime.Parse() to throw this exception ?!?
                    //This seems to be fixed in Whidbey but we cannot upgrade to it. We can ignore this since
                    //the strings are not valid dates anyways
                }
            }

            // Go through and strip out invalid fields from the search fields
            // Invalid fields = Those that dont match the datatype of the Search string
            foreach (XmlNode conditionNode in searchFields.SelectNodes("condition"))
            {
                switch (conditionNode.Attributes["value"].Value)
                {
                    case "{4}": //Float
                        if (!SearchCriteriaIsFloat)
                            searchFields.RemoveChild(conditionNode);
                        break;
                    case "{3}": //DateTime
                        if (!SearchCriteriaIsDate)
                            searchFields.RemoveChild(conditionNode);
                        break;
                    case "{2}": //Money
                        if (!SearchCriteriaIsCurrency)
                            searchFields.RemoveChild(conditionNode);
                        break;
                    case "{1}": //Integer
                        if (!SearchCriteriaIsInteger)
                            searchFields.RemoveChild(conditionNode);
                        break;
                }
            }

            //check if all the search fields were eliminated
            if (searchFields.InnerXml.Length == 0)
            {
                return string.Empty;
            }
            else
            {
            }

            // Check for GUIDs and insert an extra set of {} around the GUIDs so that
            // String.Format does not confuse the GUIDs with {0-9}
            Regex guidExp = new Regex(@"{?[A-F0-9]{8}-([A-F0-9]{4}-){3}[A-F0-9]{12}}?");
            Match guidExpMatch = guidExp.Match(searchFields.InnerXml);
            if (guidExpMatch.Success)
            {
                searchFields.InnerXml = searchFields.InnerXml.Insert(guidExpMatch.Index, "{");
                searchFields.InnerXml = searchFields.InnerXml.Insert(guidExpMatch.Index + guidExpMatch.Length, "}");
            }

            // Replace the remaining place holders {0}=String, {1}=Int, {2}=Money, {3}=Datetime, {4}=Float in the searchFields DOM
            searchFields.InnerXml = String.Format(CultureInfo.InvariantCulture, searchFields.InnerXml, SearchCriteria, SearchCriteriaAsInteger, SearchCriteriaAsDecimal, SearchCriteriaAsDate, SearchCriteriaAsDecimal);

            // NOTE: Must have a cleaner way of building the fiter xml
            // ideally we would want to use the fetch builder to be able to construct the
            // filter xml for us within a given fetch xml
            // But for now we seem to be messing with the QueryXml on the query object within
            // queryBuilder from everywhere. So we continue with that for now. When we have a
            // clean way of building the queryXml in the query object then we can use that
            // and get rid of this code.
            return queryXmlDOM.OuterXml;
        }

        /// <summary>
        /// Get the metadata given the entity name and attribute name
        /// </summary>
        /// <param name="entityName"></param>
        /// <param name="attributeName"></param>
        /// <returns></returns>
        private static AttributeMetadata GetAttributeMetadata(string entityName, string attributeName)
        {
            if ((entityName == null) || (attributeName == null))
            {
                return null;
            }

            AttributeMetadata[] attrMeta = GetEntityMetaData(entityName).Attributes;

            foreach (AttributeMetadata aMeta in attrMeta)
            {
                if (aMeta.Name == attributeName)
                {
                    return aMeta;
                }
            }
            return null;   
        }

        /// <summary>
        /// Tricky.
        /// 
        /// We need lookup columns. 
        /// get the lookup xml and get the columns. 
        /// 
        /// if that is not available, get the quick find xml and get those columns
        /// 
        /// if that too is not availabel, get the primary field
        /// 
        /// The moral of the function is that "something is better than nothing" :)
        /// </summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static string[] GetQkColumnsIfNoLookUpAvailable(string entityType)
        {
            string layoutxml = GetLookUpXmlForEntityType("layoutxml", entityType);
            if (layoutxml != null)
            {
                return getLookupAttributes(layoutxml, "/grid/row/cell", "name");
            }

            string lookUpXml = GetLookUpXmlForEntityType("fetchxml", entityType);
            if (lookUpXml != null)
            {
                return getLookupAttributes(lookUpXml, "/fetch/entity/attribute", "name");
            }

            string qkFindXml = GetFetchXmlForEntityType(entityType);
            if (qkFindXml != null)
            {
                return getLookupAttributes(qkFindXml, "/fetch/entity/attribute", "name");
            }

            string primaryFld = GetEntityMetaData(entityType).PrimaryField;
            AttributeMetadata AttrMeta = GetAttributeMetadata(entityType, primaryFld);
            string attrOfPrimaryFld = null;

            if (AttrMeta != null)
            {
                attrOfPrimaryFld = AttrMeta.AttributeOf;
            }

            if (attrOfPrimaryFld != null)
            {
                primaryFld = attrOfPrimaryFld;
            }

            if (primaryFld != null) // dont make these 2 merge.. there is logi here.
            {
                return new string[] { primaryFld };
            }
            return null;
        }

        /// <summary>
        /// Get the details of the specified entity and the specified columnset. 
        /// and also retrieve the entity as a dynamic entity.
        /// </summary>
        /// <param name="entityName"></param>
        /// <param name="guid"></param>
        /// <param name="columnSet"></param>
        /// <returns></returns>
        private static DynamicEntity GetDynamicEntity(string entityName, Guid guid, ColumnSetBase columnSet)
        {
            // Create the Retrieve Target
            TargetRetrieveDynamic targetRetrieve = new TargetRetrieveDynamic();

            // Set the Target's Properties
            targetRetrieve.EntityName = entityName;
            targetRetrieve.EntityId = guid;

            // Create the Request Object
            RetrieveRequest retrieve = new RetrieveRequest();

            // Set the Request Object's Properties
            retrieve.Target = targetRetrieve;
            retrieve.ColumnSet = columnSet;

            // Indicates that the BusinessEntity should be retrieve as a DynamicEntity
            retrieve.ReturnDynamicEntities = true;

            // Execute the Request
            RetrieveResponse retrieved = null;
            try
            {
                retrieved = (RetrieveResponse)_CrmService.Execute(retrieve);
            }
            catch
            {
                return null;
            }
            // Extract the DynamicEntity from the request
            DynamicEntity entity = (DynamicEntity)retrieved.BusinessEntity;
            return entity;
        }
        
        /// <summary>
        /// Get the specified details of the entity 
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="entityType"></param>
        /// <param name="specified"></param>
        /// <returns></returns>
        public static BusinessEntity GetSpecifiedDetailsOfThisEnity(BusinessEntity entity, string entityType, string[] specified)
        {
            if ((entityType == null) || (entity == null) || (specified == null))
            {
                return null;
            }

            BusinessEntity bE = null;
            EntityMetadata entityMeta = GetEntityMetaData(entityType);
            if (entityMeta == null)
            {
                return bE;
            }

            ColumnSet columnSet = new ColumnSet();
            columnSet.Attributes = specified;

            try
            {
                bE = GetDynamicEntity(entityType, (Guid)GetAttribute(ref entity, entityMeta.PrimaryKey), (ColumnSetBase)columnSet);
            }
            catch (Exception)
            {
                // RetrieveExp.
            }
            return bE;
        }

        /// <summary>
        /// Give the guid and type, get ALL the details of the entity.
        /// </summary>
        /// <param name="guid"></param>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static BusinessEntity GetAllDetailsOfThisEntity(Guid guid, string entityType)
        {
            if ((entityType == null) || (guid == Guid.Empty))
            {
                return null;
            }

            BusinessEntity bE = null;
            EntityMetadata entityMeta = GetEntityMetaData(entityType);
            if (entityMeta == null)
            {
                return bE;
            }

            RetrieveRequest req = new RetrieveRequest();
            req.ColumnSet = new AllColumns();

            try
            {
                bE = GetDynamicEntity(entityType, guid, (ColumnSetBase)req.ColumnSet);
            }
            catch (Exception)
            {
                // RetrieveExp.
            }
            return bE;
        }

        /// <summary>
        /// Get the guid of the referenced business entity.
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static Guid GetGuid(ref BusinessEntity entity, string entityType)
        {
            Guid guid = Guid.Empty;
            if ((entityType == null) || (entity == null))
            {
                return guid;
            }
            EntityMetadata entityMeta = GetEntityMetaData(entityType);
            if (entityMeta == null)
            {
                return guid;
            }

            guid = (System.Guid)GetAttribute(ref entity, entityMeta.PrimaryKey);
            return guid;
        }

        /// <summary>
        /// Given the entity, get all the details of it. all the columns of it.
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static BusinessEntity GetAllDetailsOfThisEntity(ref BusinessEntity entity, string entityType)
        {
            if ((entityType == null) || (entity == null))
            {
                return null;
            }

            BusinessEntity bE = null;
            EntityMetadata entityMeta = GetEntityMetaData(entityType);
            if (entityMeta == null)
            {
                return bE;
            }

            RetrieveRequest req = new RetrieveRequest();
            req.ColumnSet = new AllColumns();

            try
            {
                bE = GetDynamicEntity(entityType, (System.Guid)GetAttribute(ref entity, entityMeta.PrimaryKey), (ColumnSetBase)req.ColumnSet);
            }
            catch (Exception)
            {
                // RetrieveExp.
            }
            return bE;
        }

        /// <summary>
        /// Given an entitytype, get the layout view of it.
        /// Once retrieved get the columns whihc are "not" hidden.
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="viewName"></param>
        /// <returns></returns>
        public static string[] ColumnsFromLayOutXmlForTheView(string entityType, string viewName)
        {
            ColumnSet cSet = new ColumnSet();
            cSet.Attributes = new string[] { "layoutxml" };

            ConditionExpression c = new ConditionExpression();
            c.AttributeName = "returnedtypecode";
            c.Operator = ConditionOperator.Equal;
            c.Values = new object[] { GetObjectTypeCodeFromMetaData(entityType) };

            ConditionExpression c1 = new ConditionExpression();
            c1.AttributeName = "querytype";
            c1.Operator = ConditionOperator.Equal;
            c1.Values = new string[] { "0" };

            ConditionExpression c2 = new ConditionExpression();
            c2.AttributeName = "name";
            c2.Operator = ConditionOperator.Equal;
            c2.Values = new string[] { viewName };

            QueryExpression q = new QueryExpression();
            q.EntityName = EntityName.savedquery.ToString();
            q.ColumnSet = cSet;
            q.Criteria = new FilterExpression();
            q.Criteria.Conditions = new ConditionExpression[] { c, c1, c2 };
            q.Criteria.FilterOperator = LogicalOperator.And;
            BusinessEntityCollection b = null;

            try
            {
                b = _CrmService.RetrieveMultiple(q);
            }
            catch //  (Exception e)
            {
                return null;
            }

            if (b.BusinessEntities.Length == 1)
            {
                string layoutXml = ((savedquery)b.BusinessEntities[0]).layoutxml;
                if (layoutXml != null)
                {
                    return getLookupAttributes(layoutXml, "/grid/row/cell", "name");
                }
            }

            return null;
        }

        /// <summary>
        /// Take the view info, the entity type, search string and page info 
        /// Get the entities which match the search string and get them in the view asked
        /// and that too those records which fit in the page mentioned.
        /// </summary>
        /// <param name="searchFor"></param>
        /// <param name="viewXml"></param>
        /// <param name="pageInfo"></param>
        /// <param name="viewName"></param>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static BusinessEntityCollection GetEntitiesWithThisView(string searchFor, string viewXml, PagingInfo pageInfo, string viewName, string entityType)
        {
            if ((searchFor == null) || (viewXml == null))
            {
                return null;
            }

            BusinessEntityCollection retBec = null;
            FetchXmlToQueryExpressionRequest req = new FetchXmlToQueryExpressionRequest();

            req.FetchXml = string.Format(System.Globalization.CultureInfo.InvariantCulture, viewXml, searchFor);
            FetchXmlToQueryExpressionResponse res = null;
            try
            {
                res = (FetchXmlToQueryExpressionResponse)_CrmService.Execute(req);
            }
            catch (Exception)
            {
                return null;
            }

            if (res != null)
            {
                try
                {
                     ////Try to get layout xml.
                    if ((viewName != null) && (entityType != null))
                    {
                        string[] columns = ColumnsFromLayOutXmlForTheView(entityType, viewName);
                        if ((columns != null) && (columns.Length != 0))
                        {
                            ColumnSet colSet = new ColumnSet();
                            colSet.Attributes = columns;
                            res.Query.ColumnSet = colSet;
                        }
                    }                    

                    //Commenting out since we want to get all the search results together 
                    // in smart search
                    //((QueryExpression)res.Query).PageInfo = pageInfo;
                    retBec = RetrieveDynamicEntities(res.Query);
                }
                catch (Exception)
                {
                    // find out the type of exception
                }
            }
            return retBec;
        }

        /// <summary>
        /// Tricky again.!!
        /// 
        /// The requirement is as follows
        /// 
        /// Given the search string, search for the enties according to the quick find criteria. 
        /// But once you get the handle of the entity, rahter than getting the quickfind columns,
        /// get the lookup columns.
        /// 
        /// And the function precisely meets the requirement
        /// 
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="searchPattern"></param>
        /// <param name="pageInfo"></param>
        /// <returns></returns>
        public static BusinessEntityCollection SearchQkBringLookUp(string entityType, string searchPattern, PagingInfo pageInfo)
        {
            string lookUpXml = GetLookUpXmlForEntityType("fetchxml", entityType);
            string qkFindXml = GetFetchXmlForEntityType(entityType);

            if ((lookUpXml == null) && (qkFindXml == null))
            {
                return null;
            }

            if (lookUpXml == null)
            {
                return GetEntitiesWithThisView(searchPattern, ProcessQuickFindSearchCriteria(searchPattern, qkFindXml, entityType), pageInfo, null, null);
            }

            if (qkFindXml == null)
            {
                return GetEntitiesWithThisView(searchPattern, ProcessQuickFindSearchCriteria(searchPattern, lookUpXml, entityType), pageInfo, null, null);
            }

            FetchXmlToQueryExpressionRequest reqF = new FetchXmlToQueryExpressionRequest();
            reqF.FetchXml = ProcessQuickFindSearchCriteria(searchPattern, qkFindXml, entityType); // qkFindXml cant be null here.
            FetchXmlToQueryExpressionResponse resF = null;
            try
            {
                resF = (FetchXmlToQueryExpressionResponse)_CrmService.Execute(reqF);
            }
            catch
            {
                return null;
            }

            if (resF == null)
            {
                return GetEntitiesWithThisView(searchPattern, lookUpXml, pageInfo, null, null);
            }

            QueryExpressionToFetchXmlRequest reqQ = new QueryExpressionToFetchXmlRequest();
            reqQ.Query = resF.Query;
            string[] columns = getLookupAttributes(lookUpXml, "/fetch/entity/attribute", "name");
            if ((reqQ.Query != null) && (columns != null))
            {
                ColumnSet colSet = new ColumnSet();
                colSet.Attributes = columns;
                reqQ.Query.ColumnSet = colSet;
                try
                {

                    //Commenting out the paging information since in the new smartsearch,
                    // we want to see all information at the same time
                    //((QueryExpression)reqQ.Query).PageInfo = pageInfo;
                    return RetrieveDynamicEntities(reqQ.Query);
                }
                catch { }
            }
            return null;
        }

        /// <summary>
        /// Just want to know whehter we have any matching records. We dont need to know the details.
        /// So just do a simple search to get only the guids. Dont bring in all the details
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="searchFor"></param>
        /// <param name="pageInfo"></param>
        /// <returns></returns>
        public static BusinessEntityCollection DoRealSearchBringMinimal(string entityType, string searchFor, PagingInfo pageInfo)
        {
            BusinessEntityCollection retBec = null;
            if ((entityType == null) || (searchFor == null))
            {
                return null;
            }

            EntityMetadata entityMeta = GetEntityMetaData(entityType);
            if (entityMeta == null)
            {
                return retBec;
            }
            // only place where we need qkfind xml before lkUp xml.
            string qkFindXml = GetFetchXmlForEntityType(entityType);
            if (qkFindXml == null)
            {
                qkFindXml = GetLookUpXmlForEntityType("fetchxml", entityType);
                if (qkFindXml == null)
                {
                    return null;
                }
            }

            FetchXmlToQueryExpressionRequest req = new FetchXmlToQueryExpressionRequest();
            req.FetchXml = ProcessQuickFindSearchCriteria(searchFor, qkFindXml, entityType);
            FetchXmlToQueryExpressionResponse res = null;
            try
            {
                res = (FetchXmlToQueryExpressionResponse)_CrmService.Execute(req);
            }
            catch (Exception)
            {
                return null;
            }
            if (res != null)
            {
                ColumnSet columnSet = new ColumnSet();
                columnSet.Attributes = new string[] { entityMeta.PrimaryField };
                res.Query.ColumnSet = columnSet;
                try
                {
                    res.Query.PageInfo = pageInfo;
                    retBec = RetrieveDynamicEntities(res.Query);
                }
                catch (Exception)
                {
                    // find out the type of exception
                }
            }
            return retBec;
        }

        /// <summary>
        /// Given the query, get the entities in dynamicentity format.
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        private static BusinessEntityCollection RetrieveDynamicEntities(QueryBase query)
        {
            //ColumnSet cs = (ColumnSet)query.ColumnSet;
            //string[] attrs = cs.Attributes;
            RetrieveMultipleRequest req = new RetrieveMultipleRequest();
            req.Query = query;
            req.ReturnDynamicEntities = true;
            RetrieveMultipleResponse res = null;
            try
            {
                res = (RetrieveMultipleResponse)_CrmService.Execute(req);
            }
            catch
            {
                return null;
                // this is like the sever down. TODO - cathc the proper exception.
            }
            return res.BusinessEntityCollection;
        }

        /// <summary>
        /// Tricky!!!
        ///
        /// 1) Get all the relationships between the given entities.
        /// 2) Get the details of relationship.
        /// 3) Create the query in a way so that to get all the instances of the other entity where 
        /// the correspoding column of the related type should contain the Guid of the given entity.
        /// 4) Execute the query.
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="entityType"></param>
        /// <param name="relatedType"></param>
        /// <param name="pInfo"></param>
        /// <returns></returns>
        public static BusinessEntityCollection GetRelatedEntites(BusinessEntity entity, string entityType, string relatedType, PagingInfo pInfo)
        {
            if ((entity == null) || (entityType == null) || (relatedType == null))
            {
                return null;
            }
            EntityMetadata entityMeta = GetEntityMetaData(entityType);
            // REFERENCED_FROM SHOULD ALSO BE CHECK - needs more time. Considering as a BUG
            RelationshipMetadata[] relationsTo = entityMeta.ReferencesTo;
            RelationshipMetadata[] relationsFrom = entityMeta.ReferencesFrom;

            System.Guid guid = (Guid)GetAttribute(ref entity, entityMeta.PrimaryKey);

            entity = GetDynamicEntity(entityType, guid, new AllColumns());
            if (entity == null)
            {
                return null;
            }

            StringCollection attributes = new StringCollection();
            foreach (RelationshipMetadata relation in relationsTo)
            {
                if ((relation.ReferencedEntity == relation.ReferencingEntity) &&
                    (relation.ReferencedAttribute == relation.ReferencingAttribute))
                {
                    continue;
                }
                if ((relation.ReferencingEntity == relatedType) && (!attributes.Contains(relation.ReferencingAttribute)))
                {
                    attributes.Add(relation.ReferencingAttribute);
                }
            }
            //attributes.Remove(entityMeta.PrimaryKey);

            StringCollection attrThisE = new StringCollection();
            StringCollection attrRelE = new StringCollection();
            foreach (RelationshipMetadata relation in relationsFrom)
            {
                if ((relation.ReferencedEntity == relatedType) && (!attrThisE.Contains(relation.ReferencingAttribute)))// && (!attrRelE.Contains(relation.ReferencedAttribute)))
                {
                    attrThisE.Add(relation.ReferencingAttribute);
                    attrRelE.Add(relation.ReferencedAttribute);
                }
            }


            BusinessEntityCollection bec = null;

            try
            {
                ColumnSet cSet = new ColumnSet();
                cSet.Attributes = GetQkColumnsIfNoLookUpAvailable(relatedType);

                int attrToCount = attributes.Count;
                int attrFrCount = attrThisE.Count;
                ConditionExpression[] conditions = new ConditionExpression[attrToCount + attrFrCount];

                for (int i = 0; i < attrToCount; i++)
                {
                    ConditionExpression c = new ConditionExpression();
                    c.AttributeName = attributes[i];
                    c.Operator = ConditionOperator.Equal;
                    c.Values = new object[] { guid.ToString() };
                    conditions[i] = c;
                }

                for (int j = 0; j < attrFrCount; j++)
                {
                    ConditionExpression c = new ConditionExpression();
                    c.AttributeName = attrRelE[j];
                    c.Operator = ConditionOperator.Equal;
                    System.Guid id = Guid.Empty;
                    try
                    {
                        id = (Guid)GetAttribute(ref entity, attrThisE[j] + "Id");
                    }
                    catch
                    {
                        // neednt do anything. // will be rectified.
                    }
                    c.Values = new object[] { id.ToString() };
                    conditions[j + attrToCount] = c;
                }

                QueryExpression q = new QueryExpression();
                q.EntityName = GetEntityMetaData(relatedType).Name;
                q.ColumnSet = cSet;
                q.Criteria = new FilterExpression();
                q.Criteria.FilterOperator = LogicalOperator.Or;
                q.Criteria.Conditions = conditions;
                q.PageInfo = pInfo;

                RetrieveMultipleRequest req = new RetrieveMultipleRequest();
                req.Query = q;
                req.ReturnDynamicEntities = true;
                RetrieveMultipleResponse res = null;
                try
                {
                    res = (RetrieveMultipleResponse)_CrmService.Execute(req);
                }
                catch
                {
                    return null;
                }
                bec = res.BusinessEntityCollection;
            }

            catch (Exception)
            { }
            return bec;
        }

        /// <summary>
        /// Given the entity type, get the hardcoded part for the URL.
        /// </summary>
        /// <param name="entityDName"></param>
        /// <returns></returns>
        private static string GetPartOfURL(string entityDName)
        {
            switch (entityDName.ToLower(CultureInfo.InvariantCulture))
            {
                case "account":
                    return "sfa/accts/edit.aspx";
                case "address":
                    return "sfa/customeraddress/edit.aspx";
                case "list":
                    return "ma/lists/edit.aspx";
                case "campaign":
                    return "ma/camps/edit.aspx";
                case "bulkoperation":
                    return "ma/bulkoperations/edit.aspx";
                case "service":
                    return "sm/services/edit.aspx";
                case "campaignresponse":
                    return "ma/campaignresponse/edit.aspx";
                case "campaignactivity":
                    return "ma/campaignactivity/edit.aspx";
                case "equipment":
                    return "sm/resources/edit.aspx";
                case "resourcegroup":
                    return "sm/resourcegroups/edit.aspx";
                case "resourcespec":
                    return "sm/resourcespecs/edit.aspx";
                case "site":
                    return "sm/sites/edit.aspx";
                case "servicerestrictioncalendarrule":
                    return "sm/workplans/dialogs/serviceavailability.aspx";
                case "occurrencecalendarrule":
                    return "sm/workplans/dialogs/occurrence.aspx";
                case "recurrencecalendarrule":
                    return "sm/workplans/dialogs/recurrencerule.aspx";
                case "occurringworkshift":
                    return "sm/workplans/dialogs/timesheet.aspx";
                case "calendar":
                    return "tools/availabilitytemplateeditor/edit.aspx";
                case "contact":
                    return "sfa/conts/edit.aspx";
                case "customeraddress":
                    return "sfa/customeraddress/edit.aspx";
                case "opportunity":
                    return "sfa/opps/edit.aspx";
                case "opportunityproduct":
                    return "sfa/opportunityproduct/edit.aspx";
                case "customeropportunityrole":
                    return "sfa/customeropportunityrole/edit.aspx";
                case "lead":
                    return "sfa/leads/edit.aspx";
                case "annotation":
                    return "notes/edit.aspx";
                case "quote":
                    return "sfa/quotes/edit.aspx";
                case "quotedetail":
                    return "sfa/quotedetail/edit.aspx";
                case "salesorder":
                    return "sfa/salesorder/edit.aspx";
                case "salesorderdetail":
                    return "sfa/salesorderdetail/edit.aspx";
                case "invoice":
                    return "sfa/invoice/edit.aspx";
                case "invoicedetail":
                    return "sfa/invoicedetail/edit.aspx";
                case "systemuser":
                    return "biz/users/edit.aspx";
                case "team":
                    return "biz/teams/edit.aspx";
                case "businessunit":
                    return "biz/business/edit.aspx";
                case "incident":
                    return "cs/cases/edit.aspx";
                case "competitor":
                    return "sfa/comps/edit.aspx";
                case "documentindex":
                    return "cs/articles/viewer/default.aspx";
                case "kbarticle":
                    return "cs/articles/edit_article.aspx";
                case "kbarticlecomment":
                    return "cs/articles/comment/edit.aspx";
                case "kbarticletemplate":
                    return "tools/kbtemplateeditor/kbtemplateeditor.aspx";
                case "template":
                    return "tools/emailtemplateeditor/emailtemplateeditor.aspx";
                case "subject":
                    return "cs/subjs/edit_subj.aspx";
                case "businessunitnewsarticle":
                    return "tools/newseditor/edit.aspx";
                case "activitymimeattachment":
                    return "activities/attachment/edit.aspx";
                case "task":
                    return "activities/task/edit.aspx";
                case "fax":
                    return "activities/fax/edit.aspx";
                case "phonecall":
                    return "activities/phone/edit.aspx";
                case "email":
                    return "activities/email/edit.aspx";
                case "letter":
                    return "activities/letter/edit.aspx";
                case "appointment":
                    return "activities/appointment/edit.aspx";
                case "serviceappointment":
                    return "activities/serviceappointment/edit.aspx";
                case "contract":
                    return "cs/contracts/edit.aspx";
                case "contractdetail":
                    return "cs/contractdetails/edit.aspx";
                case "contracttemplate":
                    return "tools/contracttypemanager/edit.aspx";
                case "salesliterature":
                    return "sfa/saleslit/edit.aspx";
                case "salesliteratureitem":
                    return "sfa/saleslit/attachment_edit.aspx";
                case "product":
                    return "products/product/edit.aspx";
                case "productpricelevel":
                    return "products/productpricelevel/edit.aspx";
                case "role":
                    return "biz/roles/edit.aspx";
                case "savedquery":
                    return "tools/vieweditor/viewmanager.aspx";
                case "pricelevel":
                    return "products/pricelevel/edit.aspx";
                case "uomschedule":
                    return "products/uomschedule/edit.aspx";
                case "uom":
                    return "products/uom/edit.aspx";
                case "discounttype":
                    return "products/discounttype/edit.aspx";
                case "discount":
                    return "products/discounttypeitem/edit.aspx";
                case "queue":
                    return "tools/queuingmanager/edit.aspx";
                case "opportunityclose":
                    return "sfa/opps/closeopp.aspx";
                case "orderclose":
                    return "sfa/salesorder/cancelorder.aspx";
                case "quoteclose":
                    return "sfa/quotes/closequote.aspx";
                case "customerrelationship":
                    return "sfa/customerrelationships/edit.aspx";
                case "incidentresolution":
                    return "cs/cases/closecase.aspx";
                case "territory":
                    return "biz/territories/edit.aspx";
                case "relationshiprole":
                    return "tools/relationshiproleeditor/edit.aspx";
                case "report":
                    return "crmreports/viewer/viewer.aspx";
                case "timeoffcalendarrule":
                    return "sm/workplans/dialogs/timeoff.aspx";
                case "holidaycalendarrule":
                    return "sm/workplans/dialogs/holiday.aspx";
                case "recurringworkshift":
                    return "sm/workplans/edit.aspx";
                case "notworkingworkshift":
                    return "sm/workplans/edit.aspx";
                case "fixedmonthlyfiscalcalendar":
                    return "_grid/cmds/dlg_addquota.aspx";
                case "monthlyfiscalcalendar":
                    return "_grid/cmds/dlg_addquota.aspx";
                case "quarterlyfiscalcalendar":
                    return "_grid/cmds/dlg_addquota.aspx";
                case "semiannualfiscalcalendar":
                    return "_grid/cmds/dlg_addquota.aspx";
                case "annualfiscalcalendar":
                    return "_grid/cmds/dlg_addquota.aspx";
                case "userquery":
                    return "advancedfind/advfind.aspx";
                case "appofflinefilter":
                    return "tools/offlinedata/offlinefilter.aspx";
                case "displaystring":
                    return "tools/systemcustomization/displaystrings/edit.aspx";
                case "activityscheduling":
                    return "sm/activityscheduling/schedulingdialog.aspx";
                case "case":
                    return "cs/cases/edit.aspx";
                default:
                    return string.Empty;
            }

        }

        /// <summary>
        /// Create the URL for the given entity using the guid and other stuff.
        /// </summary>
        /// <param name="entityName"></param>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static string UrlForThisEntity(string entityName, ref BusinessEntity entity)
        {
            if ( (entityName == null) || (entity == null))
            {
                return string.Empty;
            }

            string Url = string.Empty;
            string UrlPart = GetPartOfURL(entityName);
            Guid entityGuid = (Guid)GetAttribute(ref entity, GetEntityMetaData(entityName).PrimaryKey);

            if (UrlPart == string.Empty)
            {
                int entityCode = GetObjectTypeCodeFromMetaData(entityName);
                Url = _CrmServer + "/UserDefined/edit.aspx" + "?id={" + entityGuid.ToString() + "}&etc=" + entityCode.ToString("G", System.Globalization.CultureInfo.InvariantCulture);
                //+ "&id{" + entityGuid.ToString() + ;
            }
            else
            {
                Url = _CrmServer + "/" + UrlPart + "?id={" + entityGuid.ToString() + "}";
            }
            return Url;
        }

        /// <summary>
        /// Get the objecttypecode of the entitytype from the metadata
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        private static int GetObjectTypeCodeFromMetaData(string entity)
        {
            EntityMetadata entityMeta = GetEntityMetaData(entity);
            return entityMeta.ObjectTypeCode;
        }

        /// <summary>
        /// Get the lookup xml or fetchxml for a given type on entity.
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static string GetLookUpXmlForEntityType(string xml, string entityType)
        {
            string retFetxhXml = null;

            ColumnSet cSet = new ColumnSet();
            cSet.Attributes = new string[] { xml };

            ConditionExpression c = new ConditionExpression();
            c.AttributeName = "returnedtypecode";
            c.Operator = ConditionOperator.Equal;
            c.Values = new object[] { GetObjectTypeCodeFromMetaData(entityType) };

            ConditionExpression c2 = new ConditionExpression();
            c2.AttributeName = "querytype";
            c2.Operator = ConditionOperator.Like;
            c2.Values = new string[] { "64" };

            QueryExpression q = new QueryExpression();
            q.EntityName = EntityName.savedquery.ToString();
            q.ColumnSet = cSet;
            q.Criteria = new FilterExpression();
            q.Criteria.Conditions = new ConditionExpression[] { c, c2 };
            q.Criteria.FilterOperator = LogicalOperator.And;
            BusinessEntityCollection b = null;

            try
            {
                b = _CrmService.RetrieveMultiple(q);
            }
            catch (Exception)// e)
            {
                return null;
            }
            // MORE STRICT CHECK AND EXECPTION HANDLING
            switch (b.BusinessEntities.Length)
            {
                case 0:
                    // Serious Error happened.
                    // no saved queery configured for the entity.
                    break;
                case 1:
                    if (xml == "layoutxml")
                    {
                        retFetxhXml = ((savedquery)b.BusinessEntities[0]).layoutxml;
                    }
                    else if (xml == "fetchxml")
                    {
                        retFetxhXml = ((savedquery)b.BusinessEntities[0]).fetchxml;
                    }
                    //FetchXmlBase.Add(entityType, retFetxhXml);
                    break;
                default:
                    //serious error.
                    // more than on quickfind query is not possible for any entity.
                    break;
            }
            return retFetxhXml;
        }

        public static string GetFetchXmlForEntityType(string entityType)
        {
            string retFetxhXml = null;

            ColumnSet cSet = new ColumnSet();
            cSet.Attributes = new string[] { "fetchxml" };

            ConditionExpression c = new ConditionExpression();
            c.AttributeName = "returnedtypecode";
            c.Operator = ConditionOperator.Equal;
            c.Values = new object[] { GetObjectTypeCodeFromMetaData(entityType) };

            ConditionExpression c1 = new ConditionExpression();
            c1.AttributeName = "isquickfindquery";
            c1.Operator = ConditionOperator.Like;
            c1.Values = new string[] { "1" };

            ConditionExpression c2 = new ConditionExpression();
            c2.AttributeName = "querytype";
            c2.Operator = ConditionOperator.Like;
            c2.Values = new string[] { "4" };

            QueryExpression q = new QueryExpression();
            q.EntityName = EntityName.savedquery.ToString();
            q.ColumnSet = cSet;
            q.Criteria = new FilterExpression();
            q.Criteria.Conditions = new ConditionExpression[] { c, c1, c2 };
            q.Criteria.FilterOperator = LogicalOperator.And;
            BusinessEntityCollection b = null;

            try
            {
                b = _CrmService.RetrieveMultiple(q);
            }
            catch  (Exception)
            {
                return null;
            }
            // MORE STRICT CHECK AND EXECPTION HANDLING
            switch (b.BusinessEntities.Length)
            {
                case 0:
                    // Serious Error happened.
                    // no saved queery configured for the entity.
                    break;
                case 1:
                    retFetxhXml = ((savedquery)b.BusinessEntities[0]).fetchxml;
                    //FetchXmlBase.Add(entityType, retFetxhXml);
                    break;
                default:
                    //serious error.
                    // more than on quickfind query is not possible for any entity.
                    break;
            }

            return retFetxhXml;
        }

        /// <summary>
        /// Given the entity and the name of the attribute, retrieve the value of the 
        /// attribute. Makes use of reflection so as the same code works for all types 
        /// of entities.
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="attribute"></param>
        /// <returns></returns>
        public static object GetAttribute(ref BusinessEntity entity, string attribute)
        {
            if ((entity == null) || (attribute == null))
            {
                return null;
            }

            try
            {
                if (entity.GetType() == typeof(DynamicEntity))
                {
                    DynamicEntity de = (DynamicEntity)entity;
                    IDictionary dictionary = UniversalEntity.GetDictionaryFromDynamicEntity(de);
                    return dictionary[attribute];
                }
                else
                {
                    PropertyInfo prop = entity.GetType().GetProperty(attribute);
                    if (prop != null)
                    {
                        return prop.GetValue(entity, null);
                    }
                }
            }
            catch // (Exception e) // what exception? - i think this can be eaten.
            { }
            return null;
        }

        /// <summary>
        /// From the parsed formxml, get the names of all the attributes.
        /// </summary>
        /// <param name="formXmlParsed"></param>
        /// <returns></returns>
        public static string[] GetAttributeNamesFromFormXmlIF(string[][] formXmlParsed)
        {
            StringCollection attributes = new StringCollection();
            if (formXmlParsed == null)
            {
                return null;
            }

            /* 
             * this formXmlParsed is the list of attributes listed according to the groups
             */

            /* 
             * It is a 2 dimensional string array where the first array of strings contains the names of grousp.
             * note that the first element - [0][0] - is null. or empty.
             * so, n-th element of first array says the name of the group of the n-th group which is present in n-th array.
             * now i know that you have understood this.
             */

            /* 
             * now - when i am storing the attributes in a group, first i will put the attribute field of the entity 
             * which is corresponding to the entry. then the display/description of that attribute. 
             * so EVEN indices - field name
             * ODD - display name
             */

            for (int i = 1; i < formXmlParsed.Length; i++)
            {
                if (formXmlParsed[i] == null)
                {
                    continue;
                }
                for (int j = 0; j < formXmlParsed[i].Length; j += 2)  // Even indices are fieldNames
                {
                    attributes.Add(formXmlParsed[i][j]);
                }
            }

            string[] retStringArr = new string[attributes.Count];
            attributes.CopyTo(retStringArr, 0);
            return retStringArr;
        }

        /// <summary>
        /// Given the xml, parse it out to get the collection of columns.
        /// </summary>
        /// <param name="lookUpXml"></param>
        /// <param name="selection"></param>
        /// <param name="attrName"></param>
        /// <returns></returns>
        public static string[] getLookupAttributes(string lookUpXml, string selection, string attrName)
        {
            if ((lookUpXml == null) ||
                (selection == null) ||
                (attrName == null))
            {
                return null;
            }

            XmlDocument lookUpXmlDoc = Util.CreateXmlDocument(lookUpXml);
            XmlNodeList nodes;
            nodes = lookUpXmlDoc.SelectNodes(selection);
            StringCollection tempAttribs = new StringCollection();
            foreach (XmlNode node in nodes)
            {
                XmlNode hidden = node.Attributes.GetNamedItem("ishidden");
                if ((hidden == null) || (hidden.InnerText != "1"))
                {
                    tempAttribs.Add(node.Attributes.GetNamedItem(attrName).InnerText);
                }
            }
            string[] attributes = new string[tempAttribs.Count];
            tempAttribs.CopyTo(attributes, 0);
            return attributes;
        }

    
        /// <summary>
        /// Given the xml for the Tab or section, get the value of the label. Do an xml parsing.
        /* 
         * this might turn out to be buggy.
         * this thinks we are looking for label details. 
         * assumes label ALWAYS comes as FIRST child node.
         */
        /// </summary>
        /// <param name="tabOrSectionXmlStr"></param>
        /// <param name="selection"></param>
        /// <param name="attrName"></param>
        /// <param name="defaultString"></param>
        /// <returns></returns>
        private static string getLabelDetailsOfTabAndSection(string tabOrSectionXmlStr, string selection, string attrName, string defaultString)
        {

            if ((tabOrSectionXmlStr == null) ||
                (selection == null) ||
                (attrName == null))
            {
                return defaultString;
            }

            XmlDocument tabOrSection = new XmlDocument();
            tabOrSection.LoadXml(tabOrSectionXmlStr);

            XmlNode labels = tabOrSection.SelectSingleNode("//" + selection);
            if ((labels == null) || (labels.ChildNodes.Count == 0))
            {
                return defaultString;
            }
            try
            {
                return labels.FirstChild.Attributes.GetNamedItem(attrName).InnerText;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// For a given cell, get the details of that cell
        /// </summary>
        /// <param name="singleCellXmlStr"></param>
        /// <returns></returns>
        private static string getDetailsFromSingleCell(string singleCellXmlStr)
        {
            try
            {
                XmlDocument singleCellDoc = new XmlDocument();
                singleCellDoc.LoadXml(singleCellXmlStr);
                return singleCellDoc.SelectSingleNode("//control").Attributes.GetNamedItem("datafieldname").InnerText;
            }
            catch // (Exception fE)
            { }
            return null;
        }

        /// <summary>
        /// Given the cellXml, parse and get the name and details of the cell.
        /// </summary>
        /// <param name="eType"></param>
        /// <param name="cellXmlStr"></param>
        /// <returns></returns>
        private static string[] getCellNameAndDetails(string eType, string cellXmlStr)
        {
            try
            {
                XmlDocument cellDoc = new XmlDocument();
                cellDoc.LoadXml(cellXmlStr);
                string label = null;
                string fieldName = null;
                StringCollection tmpColl = new StringCollection();
                XmlNodeList cells = cellDoc.SelectNodes("//cell");
                foreach (XmlNode cell in cells)
                {
                    label = getLabelDetailsOfTabAndSection(cell.OuterXml.ToString(), "labels", "description", null);
                   
                    fieldName = getDetailsFromSingleCell(cell.OuterXml.ToString());

                    if (fieldName == null)
                    {
                        continue;
                    }

                    if ((label == null)  || (label == string.Empty) && 
                        (((label = GetDisplayNameOfAttribute(eType, fieldName)) == null) || 
                         (label == string.Empty)))
                    {
                        continue;
                    }

                    tmpColl.Add(fieldName); // Even indices.
                    tmpColl.Add(label); // Odd indices
                }
                string[] cellDetails = new string[tmpColl.Count];
                tmpColl.CopyTo(cellDetails, 0);
                return cellDetails;
            }
            catch // (Exception fE)
            { }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="eType"></param>
        /// <param name="sectionXmlStr"></param>
        /// <returns></returns>
        private static string[] getDetailsFromSection(string eType, string sectionXmlStr)
        {
            try
            {
                XmlDocument section = new XmlDocument();
                section.LoadXml(sectionXmlStr);
                StringCollection retCollection = new StringCollection();
                XmlNode rows = section.SelectSingleNode("//rows");

                foreach (XmlNode row in rows.ChildNodes)
                {
                    string[] cellsInRow = getCellNameAndDetails(eType, row.OuterXml.ToString());
                    foreach (string s in cellsInRow)
                    {
                        retCollection.Add(s);
                    }
                }

                string[] retStrinColl = new string[retCollection.Count];
                retCollection.CopyTo(retStrinColl, 0);
                return retStrinColl;
            }
            catch // (Exception fE)
            { }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="eType"></param>
        /// <param name="tabXmlStr"></param>
        /// <returns></returns>
        private static string[][] getDetailsFromTab(string eType, string tabXmlStr)
        {
            try
            {
                XmlDocument tab = new XmlDocument();
                tab.LoadXml(tabXmlStr);
                XmlNode sections = tab.SelectSingleNode("//sections");
                int totalLength = 0;
                int sectionIndex = 1;

                /*
                 * Pleasse note that array[0][0] is null
                 */

                string[][] sectionDetails = new string[sections.ChildNodes.Count + 1][];
                sectionDetails[0] = new string[sections.ChildNodes.Count + 1];
                foreach (XmlNode section in sections.ChildNodes)
                {
                    sectionDetails[0][sectionIndex] = getLabelDetailsOfTabAndSection(section.OuterXml.ToString(), "labels", "description", "this section");
                    sectionDetails[sectionIndex] = getDetailsFromSection(eType, section.OuterXml.ToString());
                    totalLength += sectionDetails[sectionIndex].Length;
                    sectionIndex++;
                }
                /* array[0][0] contains the count of items :) */

                sectionDetails[0][0] = totalLength.ToString(System.Globalization.CultureInfo.InvariantCulture);
                return sectionDetails;
            }
            catch // (Exception fE)
            { }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static string[][] getPreviewDetails(string entityType)
        {
            string[][] retArray = new string[2][];
            string[][] previewDetails = new string[2][];
            string exportXmlStr = getFormXml(entityType);
            if (exportXmlStr == null)
            {
                return retArray;
            }
            XmlDocument exportXml = Util.CreateXmlDocument(exportXmlStr);
            XmlNode preView = exportXml.SelectSingleNode(@"/resultset/result/formxml/forms/entity/form[@type='preview']");
            string str = preView.OuterXml;
            XmlDocument preview = new XmlDocument();
            preview.LoadXml(str);
            XmlNodeList cells = preview.SelectNodes("//cell");

            previewDetails[0] = new string[cells.Count];
            previewDetails[1] = new string[cells.Count];

            int i = 0;
            foreach (XmlNode cell in cells)
            {
                XmlDocument tmp = new XmlDocument();
                tmp.LoadXml(cell.OuterXml);
                try
                {
                    previewDetails[0][i] = tmp.SelectSingleNode("//labels/label").Attributes.GetNamedItem("description").InnerText;
                    previewDetails[1][i] = tmp.SelectSingleNode("//control").Attributes.GetNamedItem("datafieldname").InnerText;
                    if ((previewDetails[0][i] == null) || (previewDetails[0][i] == string.Empty) ||
                         (previewDetails[1][i] == null) || (previewDetails[1][i] == string.Empty))
                    {
                        continue;
                    }
                    i++;
                }
                catch { }
            }

            retArray[0] = new string[i];
            retArray[1] = new string[i];
            for (int j = 0; j < i; j++)
            {
                retArray[0][j] = previewDetails[0][j];
                retArray[1][j] = previewDetails[1][j];
            }

            return retArray;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static string[][] getFormViewDescription(string entityType)
        {
            if (entityType == null)
            {
                return null;
            }

            string[][] ret = null;

            if(parsedFromXmlBase.ContainsKey(entityType))
            {
                return parsedFromXmlBase[entityType];
            }

            try
            {
                string exportXmlStr = getFormXml(entityType);
                if (exportXmlStr == null)
                {
                    parsedFromXmlBase.Add(entityType, null);
                    return null;
                }
                XmlDocument exportXml = Util.CreateXmlDocument(exportXmlStr);
                XmlNodeList entityList = null;
                // the following line was changed to the cnext one for the impersonation issue. - sands.
                // exportXml.SelectNodes(@"/ImportExportXml/Entities/Entity/FormXml/forms/entity");
                entityList = exportXml.SelectNodes(@"/resultset/result/formxml/forms/entity");

                /*
                 * the huge block below can be removed by a single SelectSingleNode.
                 */
                XmlDocument formDetails = new XmlDocument();
                foreach (XmlNode entity in entityList)
                {
                    if (entity.Attributes.GetNamedItem("name").InnerText == entityType)
                    {
                        bool canBreak = false;
                        foreach (XmlNode form in entity.ChildNodes)
                        {
                            if ((form.LocalName == "form") & (form.Attributes.GetNamedItem("type").InnerText == "main"))
                            {
                                formDetails.LoadXml(form.OuterXml.ToString());
                                canBreak = true;
                                break;
                            }
                        }
                        if (canBreak == true)
                        {
                            break;
                        }
                    }
                }

                // now formDetails contails <form>....</form> // check for null;
                XmlNode tabs = null;
                tabs = formDetails.SelectSingleNode("//tabs");

                if(tabs == null)
                {
                    parsedFromXmlBase.Add(entityType, null);
                    return null;
                }

                int tabDetailsCnt = 0;
                string[][][] tabDetails = new string[tabs.ChildNodes.Count][][];
                int totalLength = 0;
                int numberOfSections = 0;
                foreach (XmlNode tab in tabs.ChildNodes)
                {
                    string[][] tabDetail = getDetailsFromTab(entityType, tab.OuterXml.ToString());
                    numberOfSections += (tabDetail.Length - 1);
                    totalLength += Convert.ToInt32(tabDetail[0][0], System.Globalization.CultureInfo.InvariantCulture);
                    tabDetails[tabDetailsCnt++] = tabDetail;
                    //// "this gruop" SHOULD BE REPLACED WITH sTRING.eMPTY OR ASK PM FOR DEFAULT STRING
                    //ret[0][numTab] = getLabelDetailsOfTabAndSection(tab.OuterXml.ToString(), "labels", "description", "this Group");
                    //ret[numTab] = getDetailsFromTab(tab.OuterXml.ToString());
                    //numTab++;
                }

                int sectionCount = 1; // we need from one only!!
                ret = new string[numberOfSections + 1][];
                ret[0] = new string[numberOfSections + 1];

                // we need from zero
                for (int i = 0; i < tabDetails.Length; i++)
                {
                    if (tabDetails[i] == null)
                    {
                        continue;
                    }
                    // we need from one only... (because first one is names of sections)
                    for (int j = 1; j < tabDetails[i].Length; j++)
                    {
                        ret[0][sectionCount] = tabDetails[i][0][j];
                        ret[sectionCount++] = tabDetails[i][j];
                    }
                }
                parsedFromXmlBase.Add(entityType, ret);
                return ret;

            }
            catch // (Exception fE)
            { }
            parsedFromXmlBase.Add(entityType, null);
            return null;
        }

        /// <summary>
        /// For a given attribute, find out which of the databinding names should be used.
        /// </summary>
        /// <param name="eType"></param>
        /// <param name="realAttribName"></param>
        /// <returns></returns>
        public static string GetDataBoundAttribName(string eType, string realAttribName)
        {
            if ((eType == null) || (realAttribName == null))
            {
                return null;
            }

            switch (GetAttributeType(eType, realAttribName))
            {
                case AttributeType.Boolean:
                case AttributeType.DateTime:
                case AttributeType.Picklist:
                case AttributeType.Status:
                    return realAttribName + "Name";
                case AttributeType.Decimal:
                case AttributeType.Float:
                case AttributeType.Money:
                case AttributeType.Integer:
                    return realAttribName + "FormattedValue";
                default:
                    return realAttribName;
            }
        }

        /// <summary>
        /// For a set of attributes, find out which of the databinding names should be used.
        /// </summary>
        /// <param name="eType"></param>
        /// <param name="realAttribNames"></param>
        /// <returns></returns>
        public static string[] GetDataBoundAttribNames(string eType, string[] realAttribNames)
        {
            if((eType == null) || (realAttribNames == null))
            {
                return null;
            }
            string[] retArray = new string[realAttribNames.Length];
            for (int i = 0; i < realAttribNames.Length; i++)
            {
                retArray[i] = GetDataBoundAttribName(eType, realAttribNames[i]);
            }
            return retArray;
        }

        /// <summary>
        /// Given  a columnsset, get the databinding names of the columns in that columnset.
        /// </summary>
        /// <param name="eType"></param>
        /// <param name="columns"></param>
        /// <returns></returns>
        public static IDictionary GetNameToTypeMapping(string eType, ColumnSetBase columns)
        {
            if (columns == null)
            {
                return null;
            }

            return GetNameToTypeMapping(eType, ((ColumnSet) columns).Attributes);
        }

        /// <summary>
        /// Get the attribute names used in DataBinding for the attributes given in "Attrs"
        /// for a given entity 
        /// </summary>
        /// <param name="eType"></param>
        /// <param name="Attrs"></param>
        /// <returns></returns>
        public static IDictionary GetNameToTypeMapping(string eType, string[] Attrs)
        {
            if ((eType == null) || (Attrs == null))
            {
                return null;
            }

            Hashtable columns = new Hashtable();
            for (int i = 0; i < Attrs.Length; i++)
            {
                string attrName     = Attrs[i];
                AttributeType type = GetAttributeType(eType, attrName);
                if (type == AttributeType.Boolean)
                {
                    columns[attrName] = typeof(bool);
                    columns[attrName + "Name"] = typeof(string);
                }
                else if (type == AttributeType.DateTime)
                {
                    columns[attrName] = typeof(DateTime);
                    columns[attrName + "Name"] = typeof(string);
                }
                else if ( (type == AttributeType.Decimal) || 
                          (type == AttributeType.Money) )
                {
                    columns[attrName] = typeof(Decimal);
                    columns[attrName + "FormattedValue"] = typeof(string);
                }
                else if (type == AttributeType.Float)
                {
                    columns[attrName] = typeof(float);
                    columns[attrName + "FormattedValue"] = typeof(string);
                }
                else if ( (type == AttributeType.Customer) ||
                          (type == AttributeType.Lookup) ||
                          (type == AttributeType.Owner) )                            
                {
                    columns[attrName + "Id"] = typeof(Guid);
                    columns[attrName] = typeof(string);
                    columns[attrName + "Type"] = typeof(string);
                }
                else if ((type == AttributeType.Picklist) ||
                         (type == AttributeType.Status)   ||
                         (type == AttributeType.Integer) )
                {
                    columns[attrName] = typeof(int);
                    columns[attrName + "Name"] = typeof(string);
                }
                else if ((type == AttributeType.PrimaryKey) ||
                        (type == AttributeType.UniqueIdentifier))
                {
                    columns[attrName] = typeof(Guid);
                }
                else if (type == AttributeType.State)
                {
                    columns[attrName] = typeof(string);
                    columns[attrName + "Name"] = typeof(string);
                }
                else if (type == AttributeType.String)
                {
                    columns[attrName] = typeof(string);
                }
                else { } // ??
            }
            return columns;
        }

        /// <summary>
        /// Get the display names from schema names for attributes.
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="attribute"></param>
        /// <returns></returns>
        public static string GetDisplayNameOfAttribute(string entityType, string attribute)
        {

            if (entityType == null)
            {
                return string.Empty;
            }

            EntityMetadata eMeta = GetEntityMetaData(entityType);

            foreach (AttributeMetadata aMeta in eMeta.Attributes)
            {
                if (aMeta.Name == attribute)
                {
                    return aMeta.DisplayName;
                }
            }

            /* 
             * Potential BUG : if 2 attributes are present for the same entity 
             * as the attrib1 = xyz and attrib2 = xyz##Name or xyz##FormattedValue
             * then it will get a bug. that too a decent one. :)
             */
 
            if (attribute.LastIndexOf("Name", System.StringComparison.InvariantCulture) == (attribute.Length - 4))
            {
                return GetDisplayNameOfAttribute(entityType, attribute.Substring(0, (attribute.Length - 4)));
            }

            if (attribute.LastIndexOf("FormattedValue", System.StringComparison.InvariantCulture) == (attribute.Length - "FormattedValue".Length))
            {
                return GetDisplayNameOfAttribute(entityType, attribute.Substring(0, (attribute.Length - "FormattedValue".Length)));
            }        

            return string.Empty;
        }

        /// <summary>
        /// Get the display name from schema name for attribute.
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="attributes"></param>
        /// <returns></returns>
        public static string[] GetDisplayNameOfAttributes(string entityType, string[] attributes)
        {
            if ((entityType == null) || (attributes == null))
            {
                return null;
            }

            string[] realAttrNames = new string[attributes.Length];

            for (int i = 0; i < attributes.Length; i++)
            {
                realAttrNames[i] = GetDisplayNameOfAttribute(entityType, attributes[i]);
            }

            return realAttrNames;
        }

        /// <summary>
        /// Given the display name, get the real name of an atttribute.
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="attribute"></param>
        /// <returns></returns>
        public static string GetRealNameOfDisplayAttrib(string entityType, string attribute)
        {

            if (entityType == null)
            {
                return string.Empty;
            }

            EntityMetadata eMeta = GetEntityMetaData(entityType);

            foreach (AttributeMetadata aMeta in eMeta.Attributes)
            {
                if (aMeta.DisplayName == attribute)
                {
                    return aMeta.Name;
                }
            }

            return string.Empty;
        }

        /// <summary>
        /// Not used. - A bit tricky which uses a 'bit' to do a flip!! :)
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="attribute"></param>
        /// <param name="realToDisplay"></param>
        /// <returns></returns>
        public static string FlipAttribute(string entityType, string attribute, bool realToDisplay)
        {
            string ret = string.Empty;
            if ((entityType == null) || (attribute == null))
            {
                return ret;
            }

            string[][] parsedFormXmlOfEntity = getFormViewDescription(entityType);
            if (parsedFormXmlOfEntity == null)
            {
                return ret;
            }

            for (int i = 1; i < parsedFormXmlOfEntity.Length; i++)
            {
                if (parsedFormXmlOfEntity[i] == null)
                {
                    continue;
                }

                int j = 0;
                for (j = ((realToDisplay == true) ? (0) : (1)); j < parsedFormXmlOfEntity[i].Length; j += 2) // see the flipping!! :)
                {
                    if (parsedFormXmlOfEntity[i][j] == attribute)
                    {
                        ret = parsedFormXmlOfEntity[i][j + ((realToDisplay == true) ? (1) : (-1))];
                        break;
                    }
                }

                if (j < parsedFormXmlOfEntity[i].Length)
                {
                    break;
                }
            }
            return ret;
        }

        /// <summary>
        /// Given the list of attributes (display names) 
        /// get the real name of the attributes(Schema name_)
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="displayAttriutes"></param>
        /// <returns></returns>
        public static string[] GetRealNameOfDisplayAttribs(string entityType, string[] displayAttriutes)
        {
            if ((entityType == null) || (displayAttriutes == null))
            {
                return null;
            }

            string[] realAttrNames = new string[displayAttriutes.Length];

            for (int i = 0; i < displayAttriutes.Length; i++)
            {
                realAttrNames[i] = GetRealNameOfDisplayAttrib(entityType, displayAttriutes[i]);
            }

            return realAttrNames;


        }

        /// <summary>
        /// Get the formXml for a given entity.
        /// </summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        private static string getFormXml(string entityType)
        {
            ExecuteFetchRequest request = new ExecuteFetchRequest();
            request.FetchXml = string.Format(System.Globalization.CultureInfo.InvariantCulture, "<fetch output-format='xml-platform' mapping='logical'><entity name='organizationui'><attribute name='formxml'/><order attribute='version' descending='true' /><filter type='and'><condition attribute='objecttypecode' operator='eq' value='{0}'/><condition attribute='inproduction' operator='eq' value='1'/><condition attribute='formxml' operator='not-null' /></filter></entity></fetch>", GetObjectTypeCodeFromMetaData(entityType));

            ExecuteFetchResponse Response = null;
            try
            {
                Response = (ExecuteFetchResponse)_CrmService.Execute(request);
                string formXml = Response.FetchXmlResult;
                formXml = formXml.Replace("&lt;", "<");
                formXml = formXml.Replace("&gt;", ">");
                return formXml;
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static string[] GetViewsForLookupDlg(string entityType)
        {
            ColumnSet cSet = new ColumnSet();
            cSet.Attributes = new string[] { "name", "fetchxml" };

            ConditionExpression c = new ConditionExpression();
            c.AttributeName = "returnedtypecode";
            c.Operator = ConditionOperator.Equal;
            c.Values = new object[] { GetObjectTypeCodeFromMetaData(entityType) };

            ConditionExpression c1 = new ConditionExpression();
            c1.AttributeName = "querytype";
            c1.Operator = ConditionOperator.Equal;
            c1.Values = new string[] { "0" };

            ConditionExpression c2 = new ConditionExpression();
            c2.AttributeName = "queryapi";
            c2.Operator = ConditionOperator.Equal;
            c2.Values = new string[] { "" };

            QueryExpression q = new QueryExpression();
            q.EntityName = EntityName.savedquery.ToString();
            q.ColumnSet = cSet;
            q.Criteria = new FilterExpression();
            q.Criteria.Conditions = new ConditionExpression[] { c, c1};//, c2 };
            q.Criteria.FilterOperator = LogicalOperator.And;
            BusinessEntityCollection b = null;

            try
            {
                b = _CrmService.RetrieveMultiple(q);
            }
            catch //  (Exception e)
            {
                return null;
            }

            StringCollection tmpColl = new StringCollection();
            for (int i = 0; i < (2 * b.BusinessEntities.Length); i += 2)
            {
                // EVEN - name
                // ODD fetchXml
                if (((savedquery)b.BusinessEntities[i / 2]).name == null)
                {
                    continue;
                }
                string tmp1 = ((savedquery)b.BusinessEntities[i / 2]).name;
                string tmp2 = ((savedquery)b.BusinessEntities[i / 2]).fetchxml;
                if ((tmp1 != null) && (tmp2 != null))
                {
                    tmpColl.Add(tmp1);
                    tmpColl.Add(tmp2);
                }
            }
            string[] viewNamesAndXml = CollectionToArray(tmpColl);
            return viewNamesAndXml;
        }

        /// <summary>
        /// Get the list of activities which are valid for the given type of entity
        /// </summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static string[][] GetValidActivitiesList(string entityType)
        {
            StringCollection ValidActivitiesName = new StringCollection();
            StringCollection ValidActivitiesDisp = new StringCollection();

            if (!hasPrivilege(entityType, PrivilegeType.AppendTo) || !hasPrivilege("annotation", PrivilegeType.Create) || !hasPrivilege("annotation", PrivilegeType.Append))
            {
                return null;
            }

            string[][] CreatableRelatives = GetRelatedEntityList(entityType, PrivilegeType.Create);
            string[][] AppendableRelatives = GetRelatedEntityList(entityType, PrivilegeType.Append);

            StringCollection CreatableRCol = ArrayToCollection(CreatableRelatives[1]);
            StringCollection AppendableRCol = ArrayToCollection(AppendableRelatives[1]);

            if(entityType != EntityName.campaign.ToString())
            {
                CreatableRCol.Remove("campaignresponse");
            }
            // giving real names in second array
            foreach (string s in activites)
            {
                if (!CreatableRCol.Contains(s) || !AppendableRCol.Contains(s))
                {
                    continue;
                }

                if (!hasPrivilege(s, PrivilegeType.Create) || !hasPrivilege(s, PrivilegeType.Append) || !hasPrivilege(s, PrivilegeType.AppendTo))
                {
                    continue;
                }

                ValidActivitiesName.Add(s);
                ValidActivitiesDisp.Add(NameDisplayPluralMapping[s][0]);
            }
            string[][] retArray = new string[2][];
            retArray[0] = new string[ValidActivitiesName.Count];
            retArray[1] = new string[ValidActivitiesName.Count];

            ValidActivitiesName.CopyTo(retArray[1], 0);
            ValidActivitiesDisp.CopyTo(retArray[0], 0);

            return retArray;
        }

        /// <summary>
        /// Check for the permission to attach a note on the given  entity type.
        /// </summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static bool CanAttachNote(string entityType)
        {
            if (!hasPrivilege(entityType, PrivilegeType.AppendTo) || !hasPrivilege("annotation", PrivilegeType.Create) || !hasPrivilege("annotation", PrivilegeType.Append))
            {
                return false;
            }
            string[][] CreatableEntities = GetRelatedEntityList(entityType, PrivilegeType.Create);
            StringCollection CreatableEntitiesCol = ArrayToCollection(CreatableEntities[1]);
            if (CreatableEntitiesCol.Contains("annotation"))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Check for the permission to relate an activity for an entitytype.
        /// </summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static bool CanAttachActivity(string entityType)
        {
            if (ActivitiesCollection.Contains(entityType))
            { 
                // I dont think that one activity can have another activity as attached.
                // Campaign response can have any other activity as activity. 
                // Please note when u enable campaign response. 
                return false;
            }
            string[][] activityList = GetValidActivitiesList(entityType);
            if ((activityList == null) || (activityList[0].Length == 0))
            {
                return false;
            }
            return true;
        }
        
        /// <summary>
        /// Given a business entity and value. The value is set at the corresponding attribute 
        /// specified.
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="attribute"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool SetAttribute(ref BusinessEntity entity, string attribute, object value)
        {
            bool success = false;
            try
            {
                if (entity.GetType() == typeof(DynamicEntity))
                {
                    DynamicEntity de = (DynamicEntity)entity;
                    foreach (Property prop in de.Properties)
                    {
                        if ((prop != null) && (prop.Name == attribute))
                        {
                            FieldInfo field = prop.GetType().GetField("Value");
                            if (field != null)
                            {
                                field.SetValue(entity, value);
                            }
                        }
                    }
                }
                else
                {
                    PropertyInfo prop = entity.GetType().GetProperty(attribute);
                    if (prop != null)
                    {
                        prop.SetValue(entity, value, null);
                    }
                }
                success = true;
            }
            catch // (Exception e) 
            {
                success = false;
            }

            return success;
        }

        /* 
                    <%
                    RenderListItem(Util.Task, Privileges.CreateActivity);
                    RenderListItem(Util.Fax, Privileges.CreateActivity);
                    RenderListItem(Util.PhoneCall, Privileges.CreateActivity);
                    RenderListItem(Util.Email, Privileges.CreateActivity);
                    RenderListItem(Util.Letter, Privileges.CreateActivity);
                    RenderListItem(Util.Appointment, Privileges.CreateActivity);
                    RenderServiceAppointment();
                    RenderCampaignResponse();
                    %>
         */

        /// <summary>
        /// Given the entity and activity type, create a new activiy of that type,
        /// attach the given document to it and also relate the BE and the activity
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="regardingEntity"></param>
        /// <param name="FullQualifiedFileName"></param>
        /// <param name="ActivityType"></param>
        /// <param name="title"></param>
        /// <param name="optional"></param>
        /// <returns></returns>
      public static bool AttachToNewActivity(string entityType, ref BusinessEntity regardingEntity, string FullQualifiedFileName, string ActivityType, string title, ref object optional)
        {
            string[] filePath = FullQualifiedFileName.Split(new char[] { '\\' });
            string fileName = filePath[filePath.Length - 1];   
            Guid activityId = CreateActivityAndRelateToThisEntity(entityType, ActivityType, ref regardingEntity, fileName, ref optional);
            return AttachDocumentAsNote(ActivityType, activityId, FullQualifiedFileName, title, fileName);
        }

        /// <summary>
        /// Given the businessentity and the type of the activity, create a new instance of the activity 
        /// and relate that activity to the BE on focus.
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="activityType"></param>
        /// <param name="regardingEntity"></param>
        /// <param name="nameOfDoc"></param>
        /// <param name="optional"></param>
        /// <returns></returns>
        private static Guid CreateActivityAndRelateToThisEntity(string entityType, string activityType, ref BusinessEntity regardingEntity, string nameOfDoc, ref object optional)
        {
            if ((entityType == null) ||
                (activityType == null) ||
                (regardingEntity == null))
            {
                return Guid.Empty;
            }

            BusinessEntity entity = null;

            switch (activityType)
            {
                case "task":
                    entity = new task();
                    break;
                case "fax":
                    entity = new fax();
                    break;
                case "phonecall":
                    entity = new phonecall();
                    break;
                case "email":
                    entity = new email();
                    break;
                case "letter":
                    entity = new letter();
                    break;
                case "serviceappointment":
                    entity = new serviceappointment();
                    break;

                // FOR BELOW TWO ACTIVITIES MAKE SURE THAT YOU HAVE ENOUGH DATA FOR MANDATORY FIELDS
                case "appointment":
                    entity = new appointment();
                    if (optional == null)
                    {
                        return Guid.Empty;
                    }

                    DateTime[] schedule = (DateTime[])optional;
                    CrmDateTime dateTimeStart = new CrmDateTime();
                    CrmDateTime dateTimeEnd = new CrmDateTime();

                    dateTimeStart.date = schedule[0].ToString("d", System.Globalization.CultureInfo.InvariantCulture);
                    dateTimeEnd.date = schedule[1].ToString("d", System.Globalization.CultureInfo.InvariantCulture);

                    dateTimeStart.time = schedule[0].ToString("t", System.Globalization.CultureInfo.InvariantCulture);
                    dateTimeEnd.time = schedule[1].ToString("t", System.Globalization.CultureInfo.InvariantCulture);

                    dateTimeStart.Value = schedule[0].ToString();
                    dateTimeEnd.Value = schedule[1].ToString();

                    SetAttribute(ref entity, "scheduledstart", dateTimeStart);
                    SetAttribute(ref entity, "scheduledend", dateTimeEnd);
                    break;

                case "campaignresponse":
                    entity = new campaignresponse();
                    break;
                default:
                    return Guid.Empty;
            }

            Guid entityId = Guid.Empty;

            try
            {
                SetAttribute(ref entity, "description", (object)OfficeApi.GetSubjectForAttachment());
                SetAttribute(ref entity, "subject", (object)nameOfDoc);

                Owner owner = new Owner();
                owner.Value = User.UserId;
                owner.type = EntityName.systemuser.ToString();
                SetAttribute(ref entity, "ownerid", (object)owner);

                // Set the owner party to the target party
                activityparty userpartyFrom = new activityparty();
                userpartyFrom.partyid = new Lookup();
                userpartyFrom.partyid.Value = User.UserId;
                userpartyFrom.partyid.type = EntityName.systemuser.ToString();
                SetAttribute(ref entity, "from", (object)new activityparty[] { userpartyFrom });

                // A letter/Activity cant be FROM and TO the SAME user.
                // TODO : read the above line.
                // Set the owner party to the target party
                activityparty userpartyTo = new activityparty();
                userpartyTo.partyid = new Lookup();
                userpartyTo.partyid.Value = User.UserId;
                userpartyTo.partyid.type = EntityName.systemuser.ToString();
                SetAttribute(ref entity, "to", (object)new activityparty[] { userpartyTo });

                Picklist pickList = new Picklist();
                pickList.Value = 1; //TODO - remove hardoc
                SetAttribute(ref entity, "prioritycode", (object)pickList);

                Lookup regardingObject = new Lookup();
                regardingObject.type = (string)GetEntityMetaData(entityType).Name;
                regardingObject.Value = (Guid)GetAttribute(ref regardingEntity, GetEntityMetaData(entityType).PrimaryKey);
                SetAttribute(ref entity, "regardingobjectid", (object)regardingObject);

                entityId = _CrmService.Create(entity);
            }
            catch (Exception)
            {
                return Guid.Empty;
                // DO WE NEED TO SHOW CRM EXCEPTION MESSAGE OR NEED CUSTOM MESSAGE
            }
            return entityId;
        }

        /// <summary>
        /// Attach the document at the fullQualifiedFileName location to the entity represented by the guid.
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="entityGuid"></param>
        /// <param name="fullQualifiedFileName"></param>
        /// <param name="subject"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static bool AttachDocumentAsNote(string entityType, Guid entityGuid, string fullQualifiedFileName, string subject, string fileName)
        {
            bool success = false;
            if ((entityType == null) || (entityGuid == Guid.Empty) || (fullQualifiedFileName == null) || (subject == null))
            {
                return success;
            }

            string base64String = string.Empty;
            try
            {
                FileStream fs = File.Open(fullQualifiedFileName, FileMode.Open, FileAccess.Read);
                if (fs != null)
                {
                    byte[] bytes = new byte[fs.Length];
                    int bytesRead = fs.Read(bytes, 0, (int)fs.Length);
                    if (bytesRead > 0)
                        base64String = System.Convert.ToBase64String(bytes);
                    fs.Close();
                }
                
            }
            catch (Exception)
            {
                Util.ShowError(global::CRMScenarios.Resources.ErrorReadingTheFile);
                return success;
            }

            string mimeType = "application/octet-stream";
            System.Guid attachId = entityGuid;

            if (entityType != "email")
            {
                annotation note = new annotation();
                note.subject = subject;

                note.ownerid = new Owner();
                note.ownerid.type = EntityName.systemuser.ToString();
                note.ownerid.Value = User.UserId;
                note.isdocument = new CrmBoolean();
                note.isdocument.Value = true;

                EntityMetadata entityMeta = GetEntityMetaData(entityType);

                note.objectid = new Lookup();
                note.objectid.Value = entityGuid;

                note.objecttypecode = new EntityNameReference();
                note.objecttypecode.Value = entityMeta.Name;

                UploadFromBase64DataAnnotationRequest req = new UploadFromBase64DataAnnotationRequest();
                req.Base64Data = base64String;
                req.FileName = fileName;
                req.MimeType = mimeType;

                try
                {
                    attachId = _CrmService.Create(note);
                    req.AnnotationId = attachId;
                    UploadFromBase64DataAnnotationResponse res = null;
                    res = (UploadFromBase64DataAnnotationResponse)_CrmService.Execute(req);
                    success = true;
                }
                catch (Exception )
                { }
            }
            else
            {

                activitymimeattachment attachment = new activitymimeattachment();
                attachment.activityid = new Lookup();
                attachment.activityid.Value = entityGuid;attachment.activityid.type = EntityName.email.ToString();

                // This is the first attachment.
                attachment.attachmentnumber = new CrmNumber();
                attachment.attachmentnumber.Value = 1;

                UploadFromBase64DataActivityMimeAttachmentRequest req = new UploadFromBase64DataActivityMimeAttachmentRequest();
                req.Base64Data = base64String;
                req.FileName = fileName;
                req.MimeType = mimeType;

                try
                {
                    Guid attachmentId = _CrmService.Create(attachment);
                    req.ActivityMimeAttachmentId = attachmentId;
                    UploadFromBase64DataActivityMimeAttachmentResponse res = null;
                    res = (UploadFromBase64DataActivityMimeAttachmentResponse)_CrmService.Execute(req);
                    success = true;
                }
                catch (Exception )
                { }
            }
            return success;
        }

        /// <summary>
        /// Check for https in server connection
        /// </summary>
        /// <returns></returns>
        public static bool IsSecureConnection()
        {
            return (_CrmServer.IndexOf("https", System.StringComparison.InvariantCulture) == 0);
        }
    }
}
